151.反转字符串中的单词

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"

要点: 1.以 ’ ‘ 分割string,然后stringbuild.append()得到单词 2..队列【offerFirst】

3.string.join(" ", ans)【队列转换为字符串】

class Solution {
    public String reverseWords(String s) {
        //队列的方法
        //1.去头去尾“ ”
        //2.stringbuild+队列
        //3.细节处理的队列——》string的转换,String.join(" ", ans);
        int left = 0;
        int right = s.length() -1;

        while(s.length() >= 0 && s.charAt(left) == ' '){
            left++;
        }

        while(s.length() >= 0 && s.charAt(right) == ' '){
            right--;
        }
        
        StringBuilder word = new StringBuilder();
        //StringBuilder ans = new StringBuilder();
        Deque<String> ans = new ArrayDeque<>();
        while(left <= right){
            char c = s.charAt(left);

            if(word.length() != 0 && c == ' '){
                ans.offerFirst(word.toString());
                word = new StringBuilder();

            }else if(c != ' '){
                word.append(c);
            }

            left++;
        }

        if(word.length() > 0){
            ans.offerFirst(word.toString());
        }

        return String.join(" ", ans);
    }
}

78.子集

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

要点:回溯, backtrack(start,ans,path,nums),夹心饼干【add, backtrak,remove】

class Solution {
    /*    回溯的图
             []
           /      \
        [1]        [2]   [3]    ← 第一层选择(i=0,1,2)
       /    \        \
   [1,2]  [1,3]    [2,3]        ← 第二层选择
    /
 [1,2,3]                        ← 第三层选择
    
     */
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        
        backtrack(0, nums, new ArrayList(), ans);

        return ans;
    }

    public void backtrack(int start, int[] nums, List<Integer>  path, List<List<Integer>> ans){

       // ans.add(path);
       //加新的点
        
        ans.add(new ArrayList<>(path));

        for(int i = start; i < nums.length; i++){

            path.add(nums[i]);

            backtrack(i+1, nums, path, ans);

            path.remove(path.size() - 1);
        }


    }
}

46.全排列

要点,回溯:backtrack(used,ans,path,nums),夹心饼干【add,uese【ture】, backtrak,used【fasle】,remove】

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        //回溯
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        boolean[] used = new boolean[nums.length];
        int n = nums.length;
        backtrack(nums, used, path, ans);

        return ans;
        
    }

    public void backtrack(int[] nums, boolean[] used, List<Integer> path, List<List<Integer>> ans){
        if(path.size() == nums.length){
            List<Integer> temp = new ArrayList<>(path);
            ans.add(temp);
            return;
        }

        for(int i = 0; i < nums.length; i++){
            if(used[i]){
                continue;
            }else{
                path.add(nums[i]);
                used[i] = true;
                backtrack(nums, used, path, ans);
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }
        
    }
}

随机知识

LangChain与LangGraph

关于LangChain与LangGraph的区别,一个普遍的误解是认为它们是二选一的竞争关系。事实上,两者出自同一个团队,更像是一套渐进式的技术栈LangChain是快速构建LLM应用的组件库,而LangGraph则是用于编排复杂、有状态智能体工作流的引擎

LangChain和LangGraph的基本使用方法

要真正掌握LangChain和LangGraph,关键在于理解它们提供的API接口(也就是“方法”)。前者通过组件将你的指令传给LLM,后者则负责编排整个任务的流程。

🧩 LangChain:组件的核心方法

LangChain的核心在于其丰富的“组件”,每个组件都通过特定的方法与你的程序进行交互。

1. 模型交互与提示管理

核心方法 / 组件 主要用途 代码示例 (片段)
ChatOpenAI (聊天模型) 初始化并连接到特定的聊天模型(如GPT)。 model = ChatOpenAI(model="gpt-4o-mini")
.bind_tools(tools) 将一组工具“绑定”到模型,赋予其调用外部功能(如搜索引擎、计算器)的能力。 model_with_tools = model.bind_tools(tools)
PromptTemplate (提示模板) 创建一个可复用的提示词模板,支持动态变量插值。 prompt = PromptTemplate.from_template(...)
.from_messages() 从消息列表中创建聊天提示模板,常用于定义系统、用户和AI的角色。 ChatPromptTemplate.from_messages([...])

2. LCEL与Runnable协议

这是现代LangChain推荐的工作方式,通过管道符(|)和Runnable接口,将组件串联成清晰的工作流。

核心方法 / 组件 主要用途 代码示例 (片段)
| (管道操作符) 将多个Runnable组件串联起来,前一个的输出是后一个的输入。 chain = prompt \| model \| output_parser
.invoke(input) 同步执行整个链,是触发一次完整调用的最常用方法。 response = chain.invoke({"city": "Paris"})
.batch(inputs) 对一个输入列表批量执行,用于并行处理多个请求以提高效率。 responses = chain.batch([{"city": "NY"}, {"city": "LA"}])
RunnablePassthrough 在链中透传数据,或在传递前对数据进行预处理,如添加或修改字段。 RunnablePassthrough.assign(new_field=...)
RunnableParallel 用于并行执行多个任务(如同时查询天气和新闻),合并结果后再进行下一步。 RunnableParallel(weather=chain1, news=chain2)
RunnableBranch 根据输入数据执行条件路由,类似编程中的if/elif/else语句,用于实现分支逻辑。 RunnableBranch((condition1, chain1), default_chain)

3. 工具定义与调用 (Tool/Function Calling)

这是让LLM“动”起来的关键,使其能与外部世界交互。

核心方法 / 组件 主要用途 代码示例 (片段)
@tool 装饰器 将任何Python函数快速声明为工具,LLM会读取函数的docstring来理解其用途。 @tool def get_weather(city: str) -> str:
BaseTool 类 所有工具的抽象基类。当需要更复杂的工具逻辑时,可以通过继承此类来创建。 class MyComplexTool(BaseTool):
ToolCall LLM返回的“工具调用请求”对象,包含了工具名和参数,我们需要解析它来执行实际函数。 tool_call = response.tool_calls[0]
StructuredTool 用于创建具有结构化的、预定义模式(如Pydantic模型)的多参数工具的基类。 StructuredTool.from_function(...)

🌐 LangGraph:编排的核心方法

LangGraph的全部工作都围绕“状态图”(StateGraph)展开,通过节点和边来定义智能体的复杂工作流。

核心方法 / 组件 主要用途 代码示例 (片段)
StateGraph(state_schema) 构建器的构造函数。参数state_schema定义了图的数据结构(TypedDict或Pydantic模型)。 graph = StateGraph(MyState)
graph.add_node(name, func) 向图中添加一个节点func是实际业务逻辑(如模型调用、工具调用)。 graph.add_node("agent", agent_node)
graph.add_edge(source, target) 在节点间添加一条固定的、无条件的边 graph.add_edge("start", "agent")
graph.add_conditional_edges() 添加条件边,根据函数返回值动态决定下一步走向,是构建循环和分支的核心。 graph.add_conditional_edges("agent", router)
graph.set_entry_point(key) 设置图的起始节点 graph.set_entry_point("agent")
graph.compile() 编译构建器,生成一个可执行的、不可变的CompiledGraph对象。 app = graph.compile()
.invoke(input_dict) 执行编译后的图并等待最终状态,适用于批处理任务。 final_state = app.invoke({"input": "..."})
.stream(input_dict) 流式地执行图,可以在每个节点完成后实时获取状态更新,适合构建聊天应用。 for output in app.stream(...): print(output)
state.update() 在节点函数内部,通过返回一个字典来更新图的全局状态。特殊的Reducer用于处理并发更新冲突。 return {"messages": [new_message]}
ToolNode LangGraph预置的工具节点,负责解析模型输出的工具调用请求并执行,自动化了工具调用循环。 tool_node = ToolNode(tools)
Command 组合状态更新与路由控制。允许节点在执行逻辑后,直接指定下一个要跳转的节点,实现更精细的控制。 return Command(goto="other_node", update={...})
Send 用于实现Map-Reduce模式,动态地向一个目标节点发送多个任务,实现并行处理。 Send("worker_node", {"task": task_data})

💎 总结:从"学会"到"会用"

  1. 起步:从LangChain的线性链开始
    刚入门时,最常用的就是prompt | model | output_parser这个经典三件套。通过.invoke()方法运行它,你就能快速实现文本总结、翻译等任务。这能让你最快地跑通第一个AI应用。

  2. 进阶:引入LangGraph的循环与状态
    当你需要构建一个能根据前一步结果“思考”的智能体时,就到了LangGraph发挥作用的时候。它的核心套路是:

    • 定义状态:创建一个TypedDict类,明确哪些数据需要在图中流转。
    • 构建图:使用StateGraph(YourState),然后通过.add_node()添加模型调用和工具执行节点。
    • 实现循环:关键在于.add_conditional_edges()方法。通过它,你可以判断模型是否返回了工具调用,从而将流程导向工具节点,并在工具执行后自动回到模型节点,形成一个ReAct(思考-行动-观察)循环。
    • 完成流程:使用.set_entry_point()graph.compile()完成图的构建。

    python

    伪代码示例

    from langgraph.graph import StateGraph, END

    定义状态...

    class AgentState(TypedDict):
    messages: list

    定义节点函数...

    workflow = StateGraph(AgentState)
    workflow.add_node("agent", call_model)
    workflow.add_node("action", execute_tool)
    workflow.set_entry_point("agent")

    关键:根据条件建立循环

    workflow.add_conditional_edges("agent", should_act, {"yes": "action", "no": END})
    workflow.add_edge("action", "agent") # 工具执行后,总会回到agent思考
    app = workflow.compile()

希望这份对两个库常用方法的梳理,能帮你更好地驾驭它们。如果想深入了解某个特定方法,可以随时再问我。

碎碎念:后续会更新每天学习的八股和算法题,暑假实习找不到了,开始准备秋招的第3天。努力连续更新100天!今天主要是把agent项目跑起来,还是得学习agent知识呀这年头。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐