AI Agent 拆机手册:从LLM到Memory的六大核心模块实战解析
1. 这不是“更聪明的聊天机器人”一个从业十年的AI工程老兵亲手拆解AI Agent的真实骨架你肯定见过这样的场景同事在 Slack 里发个链接说“快看这个新出的 AI Agent能自动写周报、查竞品、订会议室简直像雇了个实习生”。点开 demo 视频确实行云流水——输入一句话它就调 API、搜网页、算数据、生成 Markdown最后把结果发到钉钉群。你心里一动这玩意儿我们团队能不能马上用起来别急着点头。我干这行十年从最早给客户部署 Rasa 对话系统到后来带团队做金融风控大模型应用再到最近半年天天泡在 LangChain 和 LangGraph 的源码里调 agent踩过的坑比写的代码还多。今天这篇不讲虚的“Agent 是未来”也不堆砌“LLM Tool Memory Agent”这种教科书定义。我就用你明天就能上手的实操语言把 AI Agent 拆成一块块能摸得着、看得见、改得了的零件。核心关键词你已经看到了LLM Agents、RAG、Agentic Frameworks、Towards AI - Medium——但它们背后的真实含义远比 Medium 上那些光鲜的标题党文章复杂得多。这篇文章就是给你准备的“Agent 拆机手册”。它适合三类人第一类是技术负责人需要判断该不该在 Q3 投入资源做 Agent 项目第二类是算法工程师正卡在“为什么我的 agent 总是死循环调同一个工具”第三类是业务方被销售吹得热血沸腾但想搞清楚这玩意儿到底能替你省下几个工时、又会带来多少新的运维麻烦。它不承诺“三天上手”但保证你读完能对着一份需求文档清晰地画出技术选型决策树知道哪个模块该用开源方案、哪个必须自己重写、哪个地方埋着雷——等你真正开始写第一行initialize_agent之前就把所有关键变量都列在了纸上。2. 内容整体设计与思路拆解为什么 Agent 不是“加个 Memory 就完事”的简单拼装很多人第一次接触 Agent脑子里浮现的图景是一个 LLM比如 GPT-4外面套上几层“壳”——左边接个数据库当 Memory右边连几个 API 当 Tools中间再塞个“Planning”模块当指挥官。听起来很美对吧我去年就带着这个想法给一家做跨境电商的客户做了个“智能选品助手”POC。结果呢上线第一天agent 在“分析竞品销量”这一步卡住反复调用同一个爬虫工具把对方服务器干崩了客服电话被打爆。复盘时发现问题根本不在 LLM 多强大而在于整个设计思路从根上就错了我们把它当成了一个“功能叠加”的产品而不是一个需要精密协同的“活系统”。真正的 Agent 设计是一场关于控制流、状态流和信息流的精密编排。它不像传统 Web 应用那样请求进来处理返回Agent 的生命周期是异步的、状态驱动的、甚至可能是中断恢复的。举个最直白的例子当你让 agent 去“帮我订一张下周二从北京到上海的机票”它要做的绝不是一条 SQL 查询。它得先理解“下周二”是哪天可能涉及日历计算再确认你的偏好常坐东航讨厌红眼航班然后调用航班 API 搜索拿到一堆结果后还得根据你的历史选择比如上次你抱怨过某家航空餐难吃做排序最后才生成预订链接。这整个链条里任何一个环节的失败或歧义都会导致整个流程崩塌。所以我们拆解 Agent必须从它的“操作系统”层面入手而不是“应用程序”层面。核心思路有三点缺一不可第一LLM 是“脑”但不是“CPU”。很多新手以为只要换上更强的 LLM比如从 gpt-3.5 升级到 claude-3-opusagent 就自然变强。错。LLM 在这里扮演的角色更接近于一个“高级调度员”和“模糊逻辑处理器”。它擅长的是理解意图、权衡利弊、生成自然语言指令但它极度不擅长精确的数值计算、严格的流程控制、以及对错误的鲁棒性处理。所以真正的“CPU”工作必须交给确定性的代码——比如用 Python 的datetime库算日期用pandas处理表格数据用SQLAlchemy执行数据库事务。LLM 只负责发出“去查 2025 年 6 月 18 日的航班”这个指令而具体的查询、校验、重试逻辑必须由下游代码实现。我见过太多项目把所有逻辑都塞进 prompt 里指望 LLM 自己写 SQL 或解析 JSON结果就是 70% 的时间花在 debug 提示词上而不是解决业务问题。第二Memory 不是“硬盘”而是“工作台档案馆”的混合体。这是最容易被误解的一点。很多框架文档里轻描淡写地说“加个ConversationBufferMemory就行”仿佛只是把聊天记录存下来。但真实的生产环境里Memory 的设计直接决定了 agent 的“智商”上限。它必须同时满足两个看似矛盾的需求一是“快”能在毫秒级内召回与当前任务最相关的上下文比如用户刚说的“把上周的报表发给张总”这里的“上周”和“张总”就是关键锚点二是“准”不能把无关信息比如三天前聊的午餐吃什么也一股脑塞给 LLM那只会污染它的思考。这就引出了两种截然不同的 Memory 架构路线一种是“统一向量库”把所有东西对话、文档、API 返回、用户画像都转成 embedding 存进一个 Milvus 或 Chroma 里靠语义搜索找另一种是“分层混合架构”就像一台电脑用 Redis 做高速缓存存最近 5 轮对话用 PostgreSQL 做结构化知识库存用户部门、职级、审批流再用一个专用的向量库比如 Qdrant存非结构化文档。后者开发成本高但可控性强是我们给银行客户做合规审查 agent 时唯一敢用的方案。前者上手快适合 MVP 验证但到了数据量上万条、并发上百时语义搜索的“幻觉召回”会让你怀疑人生。第三Planning 是“灵魂”但它的形态千差万别没有银弹。LangChain 文档里列了十几种 AgentType什么ZERO_SHOT_REACT_DESCRIPTION、CONVERSATIONAL_REACT_DESCRIPTION看着眼花缭乱。但本质上它们只代表两种哲学一种是“计划先行”一种是“边走边看”。前者像一个严谨的项目经理接到任务后先在脑子里列出所有步骤Research - Analyze - Draft - Review再一步步执行后者像一个经验丰富的老司机看到路况Observation就立刻调整方向盘Action不追求完美计划只求快速抵达。哪种好取决于你的任务。如果你要做的是“生成一份符合公司模板的季度财报PPT”那必须用“计划先行”因为每一步取数、制图、写文字、套模板都有严格顺序和依赖关系错一步全盘皆输。但如果你要做的是“帮用户在小红书上找一款适合油皮的防晒霜”那“边走边看”更合适因为搜索结果、用户反馈、成分表都是动态的需要 agent 实时感知、即时调整。我自己的经验是90% 的失败 Agent 项目根源都在于 Planning 模式选错了。老板想要一个“全自动”的工程师就硬上REACT结果 agent 在第一步就卡死因为 LLM 根本没能力在没有任何反馈的情况下凭空规划出完美的五步流程。这时候不如退一步用SELF_ASK_WITH_SEARCH让它先问一句“您对防晒霜有什么具体要求比如预算、品牌偏好、是否需要防水”——把不确定性交还给人类。3. 核心细节解析与实操要点六个模块每个都是能决定成败的“高压节点”现在我们把镜头拉近聚焦到 Agent 的六个核心模块。这不是概念罗列而是我在真实项目中亲手调试、优化、甚至重写过的每一个“高压节点”。每一个模块都藏着能让项目按时上线或者让你连续加班一周的细节。3.1 Agent/BrainLLM 选型不是“越大越好”而是“恰到好处”LLM 是 Agent 的“脑”但这个“脑”的性能指标和我们通常理解的“参数量”、“上下文长度”关系不大。在 Agent 场景下真正关键的三个指标是指令遵循能力Instruction Following、工具调用稳定性Tool Calling Reliability、以及推理链的简洁性Reasoning Chain Conciseness。我拿三个主流模型做过横向压测GPT-4-turbo、Claude-3-sonnet、以及本地部署的 Qwen2-72B。测试任务是“请从以下 JSON 中提取所有价格大于 1000 元的商品名称并按价格降序排列输出为纯文本列表不要任何解释。” 结果很有意思GPT-4-turbo 准确率 92%但平均响应时间 1.8 秒且有 5% 的概率会额外输出一段“我已成功完成任务”的废话Claude-3-sonnet 准确率 98%响应时间 1.2 秒输出格式 100% 稳定Qwen2-72B 准确率只有 76%因为它会把 JSON 解析当成编程题试图写 Python 代码来解决。这个测试说明什么说明在 Agent 里LLM 的首要任务不是“炫技”而是“精准执行”。它不需要写一首诗只需要把“调用 weather_tool(cityShanghai)”这个指令干净利落地输出出来。因此我的选型铁律是优先选择在tool callingbenchmark如 MT-Bench上得分最高的模型其次才是通用能力。OpenAI 的模型在这方面目前仍是标杆但代价是成本。如果你的业务对延迟极其敏感比如客服实时应答Claude-3-sonnet 是更好的平衡点。而如果你追求完全可控和数据不出域Qwen2 系列配合llama.cpp量化部署是目前最成熟的开源方案。但切记不要迷信“72B”Qwen2-7B 在经过 LoRA 微调后针对特定工具调用任务表现往往优于未经微调的 72B。微调的数据就来自你自己的 agent 运行日志——把那些 LLM 输出格式错误、工具名拼错、参数缺失的 case 收集起来就是最好的训练集。3.2 Memory短时记忆的“缓冲区溢出”陷阱比长时记忆更重要绝大多数教程都在教你如何搭建一个牛逼的向量数据库作为 Long-term Memory却没人告诉你Agent 的第一次崩溃90% 都发生在 Short-term Memory 的缓冲区里。ConversationBufferMemory看似简单但它有个致命缺陷它把所有对话轮次不分青红皂白地拼成一个超长字符串塞给 LLM。当对话进行到第 20 轮这个字符串可能长达 8000 token。而你的 LLM 上下文窗口是 32K看起来绰绰有余错。LLM 的注意力机制在处理超长文本时会对开头和结尾的信息给予更高权重而中间部分也就是你最需要的、第 15 轮提到的关键约束会被严重稀释。我亲眼见过一个 agent在第 5 轮用户明确说了“只对比 iPhone 和华为”到了第 18 轮它却开始推荐小米手机——因为它的“短期记忆”已经满了把最关键的约束给“挤”丢了。解决方案不是加大内存而是引入智能摘要Summarization。我的标准做法是在每次agent.run()执行完毕后不直接把新对话追加到 buffer而是先用一个轻量级 LLM比如 Phi-3-mini对整个 buffer 做一次摘要提炼出“用户目标”、“关键约束”、“已完成步骤”、“待办事项”四个字段再把这个结构化的摘要存进去。这样无论对话进行多少轮LLM 每次看到的永远是一个不超过 500 token 的、高度凝练的“任务快照”。这个技巧让我们的电商选品 agent 的任务完成率从 63% 直接拉升到 89%。至于 Long-term Memory我的建议是初期用 PostgreSQL 的 JSONB 字段就够了。把用户 ID 作为主键把所有长期记忆偏好、历史订单、投诉记录以结构化 JSON 形式存进去。查询时用 SQL 的操作符做高效匹配。等数据量真到了千万级再考虑迁移到向量库。别一上来就搞复杂架构那是给自己挖坑。3.3 PlanningReAct 框架的“观察-行动”循环藏着最深的调试密码LangChain 的ZERO_SHOT_REACT_DESCRIPTION是入门首选但它的“黑盒”特性也是新人最大的噩梦。你看到日志里打印出Thought: I need to search for the capital of France... Action: Search[Paris]... Observation: Paris is the capital of France...觉得一切顺利。但当它卡住时你根本不知道是Thought没生成还是Action解析失败还是Observation格式不对。这就是 ReAct 框架的“调试密码”所在它不是一个原子操作而是三个可独立验证的阶段。我的调试清单永远是这三步验证 Thought 阶段在agent.run()之前手动构造一个 prompt只喂给 LLM“用户问‘法国首都是哪里’。请只输出你的思考过程不要任何 Action 或 Observation。” 如果 LLM 无法稳定输出类似 “我需要使用搜索引擎来查找法国首都的信息” 的句子说明你的 prompt 工程或 LLM 本身就有问题别往下走了。验证 Action 阶段拿到 LLM 输出的完整字符串后用正则表达式rAction: (\w)\[(.*?)\]提取工具名和参数。如果这个正则总是匹配失败说明你的 output parser 配置错了或者 LLM 的输出格式不稳定。这时必须强制 LLM 使用 JSON Schema 输出而不是自由文本。验证 Observation 阶段确保你的每一个 tool 的返回值都是结构清晰、无歧义的。比如天气工具绝不能返回The current weather in Shanghai is cloudy with a temperature of 25°C.这种自然语言。必须返回{city: Shanghai, weather: cloudy, temperature: 25, unit: celsius}。这样LLM 下一次的Thought才能基于确定性的数据做推理而不是在猜“25°C”到底是华氏还是摄氏。这个“Observation 标准化”是我所有 Agent 项目的强制规范它省下的 debug 时间够你喝一年咖啡。3.4 Tools工具不是“插件”而是 Agent 的“手脚”必须有“健康检查”把一个 API 封装成 LangChain 的Tool三行代码就能搞定。但这只是万里长征第一步。真正的挑战在于如何让这些“手脚”在复杂环境中保持稳定、可靠、可监控。我见过最惨的案例是给一家物流公司做的运单追踪 agent。它集成了快递公司的官方 API但那个 API 的 SLA 是 99.5%意味着每天会有 43 分钟的不可用时间。结果 agent 在 API 不可用时不是优雅降级而是疯狂重试触发了对方的风控直接封禁了我们的 IP。所以每一个 Tool都必须内置“健康检查”和“熔断机制”。我的标准模板如下from tenacity import retry, stop_after_attempt, wait_exponential import logging class RobustWeatherTool(Tool): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._last_success_time 0 self._failure_count 0 retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min1, max10)) def _run(self, city: str) - str: # 1. 健康检查如果过去5分钟失败超过3次直接抛异常触发熔断 if time.time() - self._last_success_time 300 and self._failure_count 3: raise Exception(Tool health check failed. Circuit breaker open.) try: # 2. 执行真实API调用 result self._call_actual_api(city) self._last_success_time time.time() self._failure_count 0 return result except Exception as e: self._failure_count 1 logging.error(fWeather tool failed for {city}: {e}) raise e这个模板实现了三件事自动重试tenacity、熔断保护Circuit breaker、以及详细的日志追踪。有了它当 API 不可用时agent 会安静地等待而不是制造噪音。更重要的是这些日志是你后续做“Agent 行为审计”的唯一依据。每一次工具调用的成功/失败、耗时、输入参数都必须落库。没有监控的 Agent就像没有刹车的汽车。3.5 Output Parser从“自由发挥”到“机器可读”一场静默的革命LLM 的输出天生是“自由发挥”的。而 Agent 的执行引擎需要的是“机器可读”的结构化数据。Output Parser 就是这场静默革命的执行者。很多人用 LangChain 的默认 parser觉得够用。直到有一天LLM 在Action后面多打了一个空格或者把[写成了整个流程就停摆了。这暴露了默认 parser 的最大弱点它基于脆弱的字符串模式匹配而非健壮的语法解析。我的解决方案是强制 LLM 使用 JSON Schema 输出并用 Pydantic 模型做最终校验。步骤如下在 prompt 里明确告诉 LLM“请严格按照以下 JSON Schema 输出不要任何额外字符{ action: search, action_input: capital of France }”。编写一个 Pydantic 模型from pydantic import BaseModel, Field class AgentAction(BaseModel): action: str Field(..., descriptionThe name of the tool to use) action_input: str Field(..., descriptionThe input to pass to the tool)在 parser 里用json.loads()解析字符串再用AgentAction.model_validate()做类型和约束校验。如果校验失败就捕获异常记录日志并返回一个预设的“安全 fallback”动作比如action: ask_for_clarification。这个方法把 Output Parser 的错误率从 12% 降到了 0.3%。它带来的不仅是稳定性更是一种思维转变我们不再把 LLM 当作一个需要不断“哄骗”的孩子而是当作一个需要被“约束”和“引导”的专业协作者。它的自由必须在我们设定的框架内。3.6 Action Execution执行不是终点而是新状态的起点Action Execution 常被当作一个简单的“函数调用”调完就完事。但在我眼里它是整个 Agent 生命周期里状态流转最剧烈、也是最需要精心设计的一个环节。一次成功的get_weather(Shanghai)调用其影响远不止于返回一个字符串。它至少会触发三个状态变更Memory 更新必须将这次调用的结果{city: Shanghai, ...}以结构化方式写入 Long-term Memory供后续Thought引用Plan 修正如果这次调用耗时过长 3s下次遇到类似请求agent 应该主动选择一个更快的备用工具比如本地缓存这就是 Plan 的自适应Observation 注入返回的原始 JSON必须被清洗、标准化再注入到 LLM 的下一个Thought的上下文中而不是直接扔过去。我的标准 Action Execution 流程是一个闭环def execute_action(tool_name: str, tool_input: str) - dict: # Step 1: Pre-execution hook - 记录开始时间更新状态 start_time time.time() update_agent_state(executing, {tool: tool_name, input: tool_input}) # Step 2: Execute the tool raw_result tool_registry[tool_name](tool_input) # Step 3: Post-execution hook - 清洗、标准化、记录 cleaned_result standardize_result(raw_result, tool_name) execution_time time.time() - start_time log_tool_execution(tool_name, tool_input, cleaned_result, execution_time) # Step 4: Update Memory with structured data memory.update_long_term({ tool: tool_name, input: tool_input, output: cleaned_result, timestamp: datetime.now().isoformat(), duration_ms: int(execution_time * 1000) }) # Step 5: Return clean observation for next Thought return { tool: tool_name, result: cleaned_result, duration_ms: int(execution_time * 1000) }这个看似繁琐的流程换来的是 Agent 的“可预测性”。你知道每一次 Action 之后Memory 里一定有结构化数据日志里一定有可追溯的记录状态里一定有可监控的指标。这才是一个能放进生产环境的 Agent该有的样子。4. 实操过程与核心环节实现从零开始构建一个“会议纪要生成 Agent”理论讲完现在我们动手。我会带你从零开始构建一个真实业务中高频使用的 Agent会议纪要生成 Agent。它的需求很简单用户上传一段会议录音的文本转录稿Transcriptagent 自动识别与会者、总结讨论要点、提炼待办事项Action Items并生成一份符合公司模板的 Markdown 纪要。这个例子完美覆盖了所有核心模块而且避开了需要实时语音识别的复杂性让你能专注在 Agent 逻辑本身。整个过程我会展示每一行关键代码、每一个关键配置、以及每一个我踩过的坑。4.1 环境准备与依赖安装版本锁死是稳定的第一道防线别跳过这一步。Agent 项目最大的“幽灵 bug”往往来自依赖版本冲突。LangChain 的 major 版本升级经常伴随着 API 的彻底重构。我的经验是永远用pip install加上精确版本号而不是pip install langchain。以下是经过我生产环境验证的、2025 年 5 月的黄金组合# 创建干净的虚拟环境 python -m venv agent_env source agent_env/bin/activate # Linux/Mac # agent_env\Scripts\activate # Windows # 安装核心框架注意langchain-core 是 langchain 的新核心包 pip install langchain-core0.3.12 langchain0.3.12 langchain-community0.3.12 # 安装向量数据库Chroma 是最轻量、最适合起步的选择 pip install chromadb0.4.24 # 安装 LLM 接口我们用 OpenAI但接口是通用的 pip install openai1.47.0 # 安装用于文本处理的工具 pip install tiktoken0.7.0 python-dotenv1.0.1 # 安装用于结构化输出的 Pydantic pip install pydantic2.8.2为什么是这些版本因为langchain0.3.12是第一个全面拥抱langchain-core的稳定版它把LLM、Tool、Memory等抽象都定义在了langchain-core里上层langchain包只负责集成。这使得代码的可维护性大大增强。而chromadb0.4.24则修复了早期版本在高并发下内存泄漏的致命问题。记住当你看到网上教程用的是langchain0.1.x那基本可以判定它已经过时了。版本锁死不是保守而是对生产环境最基本的敬畏。4.2 LLM 初始化与 Prompt 工程让“脑”听懂你的指令我们不用默认的OpenAI()而是创建一个专门服务于“会议纪要”任务的 LLM 实例。关键在于model_kwargs的配置from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # 初始化 LLM重点在 temperature 和 model_kwargs llm ChatOpenAI( modelgpt-4-turbo, temperature0.1, # 降低随机性保证输出稳定 max_tokens2048, # 关键启用 JSON mode强制 LLM 输出合法 JSON model_kwargs{ response_format: {type: json_object} } ) # 构建一个强大的 ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一位专业的会议纪要助理。你的任务是 1. 从提供的会议转录文本中准确识别所有与会者姓名包括中文和英文。 2. 提炼出 3-5 个核心讨论要点每个要点需包含主题、主要观点和结论。 3. 提取出所有明确的待办事项Action Items每个事项必须包含负责人Owner、具体任务Task、截止日期Deadline。 4. 严格按照以下 JSON Schema 输出结果不要任何额外解释或字符 { attendees: [张三, 李四, John Smith], key_points: [ { topic: 项目进度, summary: 前端开发已完成80%后端接口联调预计下周开始。, conclusion: 整体进度符合预期风险可控。 } ], action_items: [ { owner: 王五, task: 整理并发送本次会议的详细技术方案文档, deadline: 2025-06-20 } ] }), MessagesPlaceholder(variable_namechat_history), # 用于记忆 (human, {transcript}) # 用户输入的转录稿 ])这里有两个关键点第一temperature0.1是经过大量测试后的最优值。0.0会让 LLM 过于死板有时会拒绝回答0.3又会让输出变得飘忽不定。0.1是一个很好的平衡点。第二response_format{type: json_object}是 OpenAI API 的一个隐藏宝藏。它会强制 LLM 的底层 tokenizer只生成合法的 JSON 字符从根本上杜绝了Output Parser的解析失败。你再也不用写正则去匹配Action:了。4.3 Memory 架构设计分层混合兼顾速度与精度对于会议纪要这个场景我们需要两种 MemoryShort-term: 保存本次会话的上下文比如用户之前说过“这份纪要要发给 CEO”那么生成的纪要就必须加上“呈报 CEO”字样。Long-term: 保存公司知识库比如“CEO 的名字是陈明”“公司标准纪要模板要求在末尾添加‘附件会议签到表’”。我们用ConversationBufferWindowMemory来做 Short-term它只保留最近 N 轮对话避免缓冲区溢出from langchain.memory import ConversationBufferWindowMemory # 只保留最近3轮对话防止上下文爆炸 memory ConversationBufferWindowMemory( k3, memory_keychat_history, return_messagesTrue, output_keyoutput # 指定输出字段方便后续提取 )Long-term Memory我们用 ChromaDB 来存公司知识库。首先准备知识库数据company_knowledge.json[ { id: ceo_name, content: 公司CEO的名字是陈明。, metadata: {category: people, source: HR系统} }, { id: template_rule, content: 所有正式会议纪要必须在文档末尾添加‘附件会议签到表’。, metadata: {category: process, source: 行政部规范} } ]然后加载并创建向量库import chromadb from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings # 初始化 Chroma 客户端 client chromadb.PersistentClient(path./chroma_db) # 创建一个名为 company_knowledge 的集合 collection client.create_collection(namecompany_knowledge) # 加载知识库数据 with open(company_knowledge.json, r, encodingutf-8) as f: knowledge_data json.load(f) # 将每条知识转换为 Chroma 的格式 documents [item[content] for item in knowledge_data] metadatas [item[metadata] for item in knowledge_data] ids [item[id] for item in knowledge_data] # 添加到集合 collection.add( documentsdocuments, metadatasmetadatas, idsids ) # 创建 LangChain 的 VectorStore 接口 vectorstore Chroma( clientclient, collection_namecompany_knowledge, embedding_functionOpenAIEmbeddings(modeltext-embedding-3-small) )这个设计让我们的 Agent 既能“记得住”本次对话的上下文又能“查得到”公司百年不变的规章制度。4.4 Tool 开发一个“会议纪要生成器”工具的诞生我们不调用外部 API而是自己写一个GenerateMinutesTool。这正是体现 Agent 灵活性的地方——它的 Tools可以是任何你能用代码实现的功能。from langchain.tools import BaseTool from pydantic import BaseModel, Field from typing import Optional, Dict, Any class GenerateMinutesInput(BaseModel): transcript: str Field(..., description会议转录文本必须是纯文本) format: str Field(defaultmarkdown, description输出格式可选 markdown 或 html) class GenerateMinutesTool(BaseTool): name generate_minutes description 根据会议转录文本生成结构化的会议纪要。输入必须是纯文本转录稿。 args_schema: type[BaseModel] GenerateMinutesInput def _run(self, transcript: str, format: str markdown) - str: # Step 1: 调用我们精心设计的 LLM 链 chain prompt | llm try: # 执行链传入转录稿 response chain.invoke({ transcript: transcript, chat_history: memory.chat_memory.messages }) # Step 2: 解析 LLM 的 JSON 输出 result_dict json.loads(response.content) # Step 3: 根据格式要求渲染成 Markdown 或 HTML if format markdown: return self._render_as_markdown(result_dict) else: return self._render_as_html(result_dict) except json.JSONDecodeError as e: return fJSON 解析失败: {e}. 请检查转录稿是否为纯文本。 except Exception as e: return f生成纪要时发生未知错误: {e} def _render_as_markdown(self, data: Dict[str, Any]) - str: # 这里是渲染逻辑非常关键 md f# 会议纪要\n\n md f## 与会人员\n md f- \n- .join(data.get(attendees, [])) \n\n md f## 核心讨论要点\n for i, kp in enumerate(data.get(key_points, []), 1): md f### {i}. {kp.get(topic, 未命名)}\n md f- **主要观点**: {kp.get(summary, )}\n md f- **结论**: {kp.get(conclusion, )}\n\n md f## 待办事项\n for i, ai in enumerate(data.get(action_items, []), 1): md f{i}. **{ai.get(owner, 未知)}**\n md f - 任务: {ai.get(task, )}\n md f - 截止日期: {ai.get(deadline, 未指定)}\n\n # 最后从 Long-term Memory 中检索并添加公司模板规则 template_rules vectorstore.similarity_search( query会议纪要模板要求, k1 ) if template_rules: md f## 附件\n md f{template_rules[0].page_content}\n return md # 实例化工具 generate_minutes_tool GenerateMinutesTool()这个工具的精妙之处在于它不是一个简单的“调用 LLM”而是一个完整的“数据处理流水线”。它接收原始文本调用 LLM 获取结构化 JSON再用确定性的 Python 代码将其渲染成人类可读的 Markdown。最关键的是它在最后一步还动态地从 Long-term Memory 中检索并插入了公司模板规则。这体现了 Agent 的核心价值它能把“固定规则”和“灵活推理”无缝编织在一起。4.5 Agent 初始化与运行把所有零件拧成一个能转动的轮子现在我们把前面所有的模块组装成一个真正的 Agentfrom langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.messages import HumanMessage, AIMessage # 创建 Agent 的提示词Prompt # 注意这里用的是 LangChain 0.3.x 的新范式create_tool_calling_agent agent_prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的会议纪要助理。请使用提供的工具来帮助用户生成高质量的会议纪要。), (placeholder, {chat_history}), (human, {