ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangChain核心概念解析:Prompt、Agent、Skill与MCP的模块化设计

LangChain核心概念解析:Prompt、Agent、Skill与MCP的模块化设计 1. 从LangChain的“全家桶”说起为什么我们需要理清这些概念如果你最近在折腾大语言模型应用开发尤其是基于LangChain这个框架那你大概率会被一堆听起来很酷但又有点模糊的词汇包围Prompt、Agent、Skill、MCP。它们频繁出现在教程、项目文档和社区讨论里有时候感觉它们是一回事有时候又好像各有各的地盘。我刚开始接触时也犯晕心想这不就是个调用API的框架吗怎么整出这么多“黑话”后来在几个实际项目中踩了坑才明白LangChain的设计哲学远不止是“封装API调用”。它试图构建一个完整的、模块化的LLM应用开发生态。而Prompt、Agent、Skill、MCP这四个概念恰恰是这个生态里不同层次的“积木块”分别负责指令表达、任务执行、能力封装和工具扩展。理不清它们的关系就像玩乐高时分不清基础砖、特殊件和动力组搭出来的东西要么功能残缺要么结构混乱。简单来说你可以把LangChain想象成一个智能机器人的组装工厂Prompt是给这个机器人的工作指令单告诉它“做什么”以及“按什么格式做”。Agent是机器人的中央决策大脑它阅读指令单决定调用哪些工具并协调整个执行流程。Skill是机器人已经预装好的内置技能包比如“计算器”、“文件阅读器”。MCP则是为机器人安装新技能工具的标准化接口协议让你能轻松给它装上“联网搜索”、“数据库查询”等外部能力。接下来我们就抛开那些笼统的定义深入到LangChain的实际代码和设计逻辑里把这四块“积木”如何咬合、协作以及你在实际开发中该如何运用它们一次讲透。2. Prompt一切交互的起点与蓝图在LangChain的语境下Prompt远不止是一个简单的输入字符串。它是你与大模型沟通的结构化契约定义了任务的上下文、格式约束以及你期望的产出。一个设计良好的Prompt是构建稳定、可靠LLM应用的基石。2.1 Prompt Templates超越字符串拼接最基础的Prompt就是一个问题比如“法国的首都是哪里”。但在实际应用中我们需要动态生成Prompt。LangChain提供了PromptTemplate这不仅仅是字符串格式化如f-string它更是一种结构化管理。from langchain.prompts import PromptTemplate # 一个简单的模板 template “请根据以下上下文回答问题\n上下文{context}\n问题{question}\n答案” prompt_template PromptTemplate.from_template(template) # 动态填充 filled_prompt prompt_template.format(context“巴黎是法国的首都和文化中心。” question“法国首都是哪里”) print(filled_prompt)为什么需要PromptTemplate而不用f-string输入变量管理它明确声明了所需的输入变量{context},{question}便于框架进行验证和自动化组装尤其在复杂链Chain中能避免变量传递错误。模板复用与组合模板可以像乐高一样被组合。例如你可以有一个“提取关键信息”的模板和一个“总结信息”的模板然后将它们串联起来。支持不同模型格式对于Chat模型如GPT-4 Claude输入是消息列表System, Human, AI。LangChain提供了ChatPromptTemplate来优雅地构建这种对话。from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate system_template “你是一个专业的翻译助手擅长将中文翻译成地道英文。” human_template “请翻译{text}” chat_prompt ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template(system_template), HumanMessagePromptTemplate.from_template(human_template) ]) messages chat_prompt.format_messages(text“今天天气真好”) # messages 现在是一个列表包含SystemMessage和HumanMessage可以直接发送给Chat模型。实操心得一System Prompt的威力很多新手会忽略System Message直接把指令放在Human Message里。但在实际使用中System Prompt是设定AI角色和行为准则的关键位置。比如你可以在这里严格规定“你是一个代码安全审查助手必须指出任何可能的安全漏洞如SQL注入、XSS等。你的输出必须首先给出‘安全评级高危/中危/低危’然后列出问题。” 这比在每次用户提问中重复这些约束要有效和稳定得多。2.2 Few-Shot Prompting让示例说话对于复杂任务光靠指令描述不够需要提供例子。FewShotPromptTemplate就是干这个的。from langchain.promshots import FewShotPromptTemplate, PromptTemplate # 1. 先定义示例集合 examples [ { “input”: “这个电影太精彩了演员演技炸裂”, “output”: “情感正面主题电影评价” }, { “input”: “快递延误了三天客服也联系不上非常失望。”, “output”: “情感负面主题物流投诉” } ] # 2. 定义单个示例的格式模板 example_template “输入{input}\n输出{output}” example_prompt PromptTemplate.from_template(example_template) # 3. 组装FewShot模板 few_shot_template FewShotPromptTemplate( examplesexamples, example_promptexample_prompt, # 每个例子怎么展示 prefix“请根据示例对以下用户输入进行情感和主题分类。\n”, # 前缀指令 suffix“输入{user_input}\n输出”, # 后缀留出位置给新输入 input_variables[“user_input”], # 新输入变量 example_separator“\n\n” # 例子之间的分隔符 ) result few_shot_template.format(user_input“这款手机电池续航太差了。”) print(result)为什么这样做更有效大模型是模式匹配的高手。提供清晰的输入-输出示例对比用自然语言长篇大论地描述规则更能让模型捕捉到你想要的输出格式和逻辑。这在做文本分类、格式化提取如从邮件中提取订单号、日期、风格模仿等任务时效果显著。踩坑记录示例的选择与顺序示例不是随便选的。我曾在一个信息提取任务中发现模型偶尔会“胡编”一个不存在的字段。排查后发现是因为我的示例里某个字段在所有例子中都有值。模型学到了“这个字段必须出现”的强关联即使新输入中没有它也会生成一个。解决方案确保示例集覆盖了边界情况比如某些字段为空的情况。同时示例的顺序有时也会有微弱影响可以把最典型、最清晰的例子放在前面。3. Agent具备“思考-行动”循环的自主执行体如果说Prompt是静态的蓝图那么Agent就是动态的项目经理。它的核心能力是根据目标来自Prompt和当前状态自主决定下一步该调用哪个工具Tool并持续循环直到任务完成或无法进行。这是LangChain将LLM从“聊天机器”升级为“智能体”的关键。3.1 Agent的核心三要素一个典型的LangChain Agent由三部分组成LLM提供推理和决策能力。ToolsAgent可以调用的外部函数或API集合如搜索、计算、数据库查询。Agent Executor驱动整个“思考-行动-观察”循环的运行时引擎。from langchain.agents import initialize_agent, AgentType from langchain.agents import Tool from langchain.llms import OpenAI from langchain.utilities import SerpAPIWrapper # 1. 定义工具 search SerpAPIWrapper() tools [ Tool( name“Search” funcsearch.run, description“在互联网上搜索最新信息。当你需要回答关于实时事件、新闻或未知事实的问题时使用此工具。” ), # 可以定义更多工具如计算器、数据库查询等 ] # 2. 初始化LLM和Agent llm OpenAI(temperature0) # temperature0让输出更确定 agent initialize_agent( tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, # 一种经典的Agent类型 verboseTrue # 开启详细日志方便观察思考过程 ) # 3. 运行Agent result agent.run(“特斯拉最新的电动卡车Semi续航里程是多少它比竞争对手有什么优势”)当你运行这段代码并开启verboseTrue你会看到类似下面的输出这就是Agent的“内心独白” Entering new AgentExecutor chain... 我需要找到特斯拉Semi卡车的续航里程信息并与其他竞争对手比较。我应该先搜索最新信息。 Action: Search Action Input: “特斯拉 Semi 续航里程 最新” Observation: [搜索引擎返回的结果特斯拉Semi续航里程约500英里...] Thought: 现在我有了续航数据还需要了解竞争对手的情况比如Freightliner eCascadia。 Action: Search Action Input: “Freightliner eCascadia 续航里程” Observation: [搜索结果Freightliner eCascadia续航约230英里...] Thought: 现在我有足够的信息进行比较了。我可以总结回答了。 Final Answer: 特斯拉Semi的续航里程约为500英里而其主要竞争对手如Freightliner eCascadia的续航约为230英里。因此特斯拉Semi在续航方面具有显著优势... Finished chain.关键点解析AgentType.ZERO_SHOT_REACT_DESCRIPTION是一种Agent类型它遵循“Reason Act”模式。LLM会根据每个Tool的description来决定使用哪个。description的撰写至关重要必须清晰说明工具的用途和适用场景这是Agent能否正确选择工具的关键。3.2 不同的Agent类型与选择LangChain提供了多种预定义的Agent类型适用于不同场景Agent 类型核心特点适用场景注意事项ZERO_SHOT_REACT_DESCRIPTION零样本无需示例基于工具描述进行推理和行动。最常用、最通用。大多数需要多步工具调用的任务。工具描述必须精确。复杂逻辑可能出错。STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION专为处理结构化工具输入参数有明确定义设计。LLM的输出会被严格解析。工具输入参数复杂需要严格格式化的场景。需要为工具定义好输入模式schema。OPENAI_FUNCTIONS/OPENAI_MULTI_FUNCTIONS利用OpenAI模型原生的函数调用Function Calling能力。与OpenAI API集成度最高可靠性好。主要使用OpenAI模型且工具定义符合其函数调用格式。绑定于OpenAI模型迁移性稍差。CONVERSATIONAL_REACT_DESCRIPTION在REACT基础上增加了对话历史的管理能力。多轮对话中需要持续使用工具的场景。需要妥善管理较长的对话历史。SELF_ASK_WITH_SEARCH专门用于复杂问答其策略是先将复杂问题拆解成多个可搜索的子问题。事实核查、复杂逻辑推理问答。通常与搜索工具配对使用。选择建议对于新手从ZERO_SHOT_REACT_DESCRIPTION开始它最直观。如果使用OpenAI的模型强烈推荐尝试OPENAI_FUNCTIONS它在工具调用的准确性和格式遵从性上通常表现更好。对于需要复杂参数的工具使用STRUCTURED_CHAT变体。3.3 Agent的局限性与调试技巧Agent看起来很智能但它也会“犯傻”。常见问题循环调用Agent陷入“思考-调用无效工具-再思考”的死循环。工具选择错误错误理解了工具描述选错了工具。参数格式错误生成的工具输入参数不符合要求。调试与优化策略开启verbose模式这是最重要的第一步观察Agent的完整思考链Chain of Thought。优化工具描述将描述写得像“给一个外星人看的说明书”极其清晰、无歧义。包括输入是什么、输出是什么、何时使用、何时不使用。例如一个计算器的描述不应只是“进行数学计算”最好是“对明确的数学表达式如’(125)*3’进行计算。不要用于文本处理或逻辑推理。”设置max_iterations在初始化Agent Executor时设置max_iterations10或其他合理值防止无限循环。使用handle_parsing_errorsTrue当LLM的输出无法被解析为有效的工具调用时这个参数可以让Agent尝试修复或给出友好错误而不是直接崩溃。agent_executor initialize_agent( tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, verboseTrue, max_iterations10, handle_parsing_errorsTrue # 处理解析错误 )实操心得二给Agent“画个圈”不要指望Agent能处理完全开放的世界。在实际项目中通过System Prompt为Agent设定明确的边界和规则极其重要。例如“你是一个内部数据查询助手。你只能使用‘查询员工信息’和‘查询部门预算’这两个工具。对于任何与查询无关的请求如聊天、创作、翻译你都必须拒绝并回答‘我仅支持内部数据查询功能’。你的回答必须简洁、专业。” 这能极大减少Agent的“幻觉”和误操作。4. Skill与Tool能力的具象化封装在LangChain的讨论中“Skill”和“Tool”这两个词经常混用但它们在我的理解中有微妙的层次区别。4.1 Tool原子操作Tool是一个具体的、可执行的函数它是Agent能够调用的最小能力单元。在代码层面它就是前面例子中的Tool对象包含namefuncdescription。一个Tool做一件事比如“搜索”、“计算”、“查询数据库”。from langchain.agents import Tool import math def calculate_power(base: float, exponent: float) - float: “”“计算幂运算。”“” return math.pow(base, exponent) power_tool Tool( name“PowerCalculator” funccalculate_power, description“计算一个数的幂。输入应该是一个包含底数和指数的字符串用逗号分隔例如 ‘2,3’ 表示计算2的3次方。” )4.2 Skill复合能力或领域专长Skill更像是一个业务层面的概念指的是一组相关的Tools或一套处理特定领域问题的“方法论”或“工作流”。它可能对应一个更复杂的Chain或者是一组协同工作的Tools。例如一个“客户服务Skill”可能包含Tool1:search_knowledge_base(搜索知识库)Tool2:escalate_to_human(转接人工)Tool3:generate_followup_email(生成跟进邮件)以及一个协调这些工具的特定Agent或Chain。在LangChain的早期版本或某些社区讨论中“Skill”可能被用来指代一个预定义好的、可复用的Agent或Chain模块。虽然当前核心库中“Skill”不是一个非常突出的官方抽象但这个概念在构建复杂应用时非常有用。你可以把自己封装好的一套解决特定问题的工具链和逻辑称为一个“Skill”。核心关系多个Tools可以组合成一个Skill。Agent通过调用一个或多个Tools来实现一个Skill所要完成的任务。例如实现“旅行规划”这个SkillAgent可能需要依次调用“搜索航班”、“查询天气”、“查找酒店”等多个Tools。4.3 如何设计与封装好的Tool功能单一一个Tool只做一件事。这有利于Agent理解和精确调用。描述精准description字段是Tool的“使用说明书”。要用自然语言清晰说明功能、输入格式最好有示例、输出什么、什么情况下用。错误处理Tool的函数内部应该有健壮的错误处理try-catch返回清晰的错误信息而不是让整个Agent崩溃。考虑结构化输入对于复杂输入考虑使用StructuredTool它可以定义严格的输入参数模式Pydantic模型让LLM更准确地生成参数。from langchain.tools import StructuredTool from pydantic import BaseModel, Field class PowerInput(BaseModel): base: float Field(description“底数”) exponent: float Field(description“指数”) def calculate_power_structured(base: float, exponent: float) - float: return math.pow(base, exponent) structured_power_tool StructuredTool.from_function( funccalculate_power_structured, name“StructuredPowerCalculator” description“计算幂运算。”, args_schemaPowerInput # 指定输入模式 )使用StructuredTool配合STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION类型的Agent可以极大提升复杂参数传递的准确性。5. MCP打破边界连接外部世界的协议MCPModel Context Protocol是LangChain生态中一个相对较新但极其重要的概念。你可以把它理解为Tool的“标准化插座”和“应用商店”。5.1 MCP要解决什么问题在没有MCP之前为你的LangChain应用添加一个新工具比如连接公司内部的JIRA系统、一个特殊的数据库、一个硬件设备API通常需要自己写Python代码封装API调用。将其包装成LangChain的Tool对象。可能还需要处理认证、错误重试、速率限制等琐事。这个工具和你的应用代码是紧耦合的。MCP旨在通过一个标准化的协议将工具提供者Server和工具消费者Client如LangChain Agent解耦。任何实现了MCP Server的程序都可以将其能力以“工具”的形式暴露出来。而LangChain应用作为Client可以通过标准方式发现并调用这些工具无需关心Server是用什么语言Go Rust Java实现的也无需将其代码直接集成到自己的项目中。5.2 MCP的核心组件与工作原理MCP Server提供工具的服务端。它向客户端宣告自己提供了哪些工具每个工具也有名称、描述、参数模式。当客户端调用某个工具时Server执行相应的逻辑并返回结果。例如一个“天气查询MCP Server”、一个“公司CRM数据MCP Server”。MCP Client消费工具的客户端。LangChain框架可以作为一个MCP Client。它连接到MCP Server获取工具列表并将这些工具“注入”到Agent的可用工具列表中。传输层MCP Server和Client之间通过标准方式通信目前主要支持stdio标准输入输出和SSE服务器发送事件。Stdio模式通常用于本地进程间通信SSE用于远程HTTP通信。工作流程Client启动连接到指定的MCP Server例如通过一个启动命令或一个URL。Client向Server发送initialize请求建立连接。Client发送tools/list请求获取Server提供的所有工具列表。Client将这些工具“翻译”成LangChain Agent能识别的Tool对象。当Agent决定使用某个MCP工具时Client向Server发送tools/call请求附带参数。Server执行并返回结果Client将结果返回给Agent。5.3 在LangChain中使用MCP工具目前LangChain对MCP的原生集成在快速发展中。通常你需要使用langchain-mcp适配器或类似的库。一个概念性的使用步骤是启动或连接MCP Server这取决于Server的部署方式。可能是运行一个本地可执行文件也可能是连接到一个远程HTTP端点。创建MCP Client并加载工具# 假设使用 langchain-mcp 库请以官方最新文档为准 from langchain_mcp import MCPClient # 连接到本地通过stdio运行的MCP Server client MCPClient(server_command[“path/to/your/mcp-server”]) # 或者连接到远程SSE Server # client MCPClient(server_url“http://localhost:8080/sse”) # 获取工具并转换为LangChain Tool对象 mcp_tools client.get_tools()将MCP Tools注入Agentfrom langchain.agents import initialize_agent from langchain.llms import OpenAI llm OpenAI(temperature0) # 将MCP工具和你本地定义的其他工具合并 all_tools [local_tool_1, local_tool_2] mcp_tools agent initialize_agent( all_tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, verboseTrue ) # 现在Agent就可以使用来自MCP Server的工具了 result agent.run(“查询纽约明天的天气然后计算如果下雨我行程延误的概率假设基础延误率10%下雨增加30%”) # Agent可能会先调用“天气查询MCP工具”再调用本地的“概率计算工具”。5.4 MCP带来的范式转变与社区生态MCP的出现让LangChain生态从“框架中心化”向“协议生态化”演进。工具即插即用未来可能会出现一个“MCP工具市场”你可以像安装插件一样为你Agent添加各种能力日历管理、社交媒体发布、智能家居控制而无需修改核心应用代码。语言无关性工具提供者可以用任何语言编写只要遵循MCP协议即可。这解放了工具开发者的技术栈。安全与管控企业可以部署内部的MCP Server统一管理对敏感系统数据库、内部API的访问权限然后让不同的AI应用通过安全的MCP协议来消费这些能力而不是在每个应用里硬编码密钥和连接逻辑。实操心得三从MCP Server开始理解要真正理解MCP最好的方法是尝试运行一个现有的MCP Server。例如可以找一些开源的MCP Server实现比如连接SQLite数据库的Server、调用GitHub API的Server。先不看LangChain单独运行Server用简单的客户端甚至可以用curl或写个小脚本模拟MCP Client去和它通信看看它如何宣告工具、如何被调用。这个过程能让你深刻理解“协议”的含义之后再将其集成到LangChain中就会水到渠成。6. 四者关系总览与实战架构设计现在让我们把Prompt、Agent、Skill、MCP放回同一个画面看看它们是如何协同工作的。[用户目标] - (被构造成) - [Prompt] - (驱动) - [Agent] | v [Agent 决策循环]思考 - 选择工具 - 执行 - 观察结果 - 再思考... | v 可用的工具库包括 1. 本地定义的 [Tools] (原子功能如计算) 2. 由多个Tools组合成的业务级 [Skill] (如“数据分析技能包”) 3. 通过 [MCP Client] 从外部 [MCP Server] 动态获取的远程工具 (如“天气服务”、“股票数据”) | v [最终结果] - (整合所有工具执行结果) - [Agent]一个实战场景智能数据分析助手假设我们要构建一个助手用户可以用自然语言提问它自动查询数据库、进行数据处理并生成图表。Prompt设计System Prompt “你是一个数据分析专家。用户会提出关于业务数据的问题。你需要根据问题决定是否需要查询数据库、进行何种计算、以及生成何种可视化。你的最终输出应该是一个包含关键数据摘要和图表生成建议的完整回答。”User Prompt “帮我分析一下上季度华东区各产品的销售额占比并告诉我哪种产品增长最快。”Agent与Tools/SkillAgent 采用OPENAI_FUNCTIONS类型因为它对结构化工具调用支持好。Tools/Skillquery_sales_db(Tool): 一个连接到数据仓库的查询工具输入是SQL语句。calculate_growth_rate(Tool): 计算增长率、占比的数学工具。DataVizSkill(Skill): 这是一个“技能包”它内部可能封装了判断图表类型饼图、折线图的逻辑并调用对应的generate_pie_chart或generate_line_chart工具这些工具可能调用Matplotlib或Plotly的API。fetch_market_trend(MCP Tool): 通过MCP连接到一个外部的市场情报服务获取行业基准数据用于对比。工作流Agent接收到Prompt。Agent思考需要销售额数据 - 调用query_sales_db生成SQL“SELECT product, sales_amount FROM sales WHERE region‘East China’ AND quarter‘Q3’”。拿到数据后思考需要计算占比和增长率 - 调用calculate_growth_rate工具传入本期和上期数据。思考需要可视化展示占比 - 调用DataVizSkill该技能包内部决定使用饼图并调用generate_pie_chart工具。思考需要行业对比来判断增长是否健康 - 调用fetch_market_trend这个MCP工具。整合所有结果生成最终回答“上季度华东区销售额占比为产品A 40%产品B 35%... 其中产品C增长率达15%远超行业平均的5%。已生成饼图附件。建议重点关注产品C的供应链以支持其增长势头。”在这个架构里Prompt是目标和约束Agent是总指挥Skill/Tool是各种专业工人MCP则是让外部专家其他系统临时加入项目组的标准化协作流程。通过这样的分层和模块化设计系统的可维护性、可扩展性都得到了极大提升。你可以独立升级某个工具比如更换图表库可以随时接入新的外部服务通过MCP而无需重写核心的Agent逻辑。这才是LangChain这套概念体系希望引导开发者走向的工程化实践。
返回列表