老王是公司里的资深工程师,工位上常年摆着三块屏幕。每天早上一打开代码托管平台,二十几个 PR 排着队等他 review。他不是不乐意审,是真审不动——光是把每个 PR 的改动看完就要大半天,更别提还要查规范、追漏洞、跑测试。结果呢?常常审到第 15 个 PR 时眼皮打架,一个 SQL 注入就这么从眼皮底下溜了过去,上线第二天数据库就被拖走了。
新人的处境也没好到哪去。小李刚入职,兴冲冲提了第一个 PR,挂在那儿三天没人看。等到终于有人路过点了两下,留下一句"看着没问题"就 approve 了。一周后线上告警,回过头一查,问题就藏在那段没人认真看过的代码里。
这两端的痛,指向同一件事:代码审查这件事,光靠人盯,是盯不住的。 于是有了本章的主角——代码审查 Agent。我们要让 Agent 像老王一样审代码:会读文件、会搜模式、会从安全/性能/规范三个维度挑刺,还会跑测试验证。区别只有一点:Agent 不会打瞌睡,也不嫌 PR 多。
全书主线进度 :第 4 章的 RAG Agent 让 Agent 学会了查资料,但它干活还是"一问一答"——你说一句,它用一次工具,回一句。真实任务可比这复杂多了。代码审查就是典型:要"读文件 → 搜模式 → 安全审查 → 性能审查 → 规范审查 → 建议修复 → 跑测试验证"。这是多轮、多维度、还得自我修正 的活儿。本章攻克两个关键能力:Harness 循环 (让 Agent 反复地想-做-看-再想)和 Skill 封装 (把审查方法论打包成可复用模块)。
主讲能力 :Harness 循环 + Skill 技能封装
业务场景 :自动审查代码变更,检查安全漏洞、性能问题、编码规范,输出结构化审查报告。
技术栈 :LangChain v1.0 create_agent + 三个审查 Skill + 文件读写/搜索/测试工具
5.1 老王的心愿
5.1.1 业务背景与痛点
把老王和小李的遭遇拆开看,代码审查的痛其实就四条:
初级工程师的代码,缺一个经验老到的审查者把关;
安全漏洞(SQL 注入、XSS)藏在 PR 里,人眼一晃就过;
同一类规范问题被反复指出,审的人烦、改的人也烦;
修完没人自动验证,按下葫芦浮起瓢,引入新问题。
人工审查的覆盖面有限,效率还会随团队扩大直线下降。既然如此,能不能把"老王式的审查"固化下来,让 Agent 不知疲倦地干?这就是本项目要回答的问题。
5.1.2 用户故事
把上面的痛翻译成一张用户故事表,需求就清晰了:
编号
作为
我想要
以便
US-1
开发者
PR 提交后立刻得到自动化审查报告
修复问题后再找同事审查
US-2
架构师
审查覆盖安全、性能、规范三个维度
不会漏掉关键问题
US-3
Tech Lead
审查报告结构化(JSON),便于接入 CI
在 CI 中自动拦截高危问题
US-4
开发者
审查后可选地自动运行测试
确认修复不引入回归
5.1.3 功能性需求
FR-1 文件读取 :Agent 能读取待审查的文件内容
FR-2 代码搜索 :Agent 能用 grep 搜索潜在问题模式(如硬编码密钥)
FR-3 三维度审查 :安全、性能、规范逐维度进行
FR-4 结构化报告 :JSON 格式,含文件路径、行号、严重程度、修复建议
FR-5 测试执行 :可选地运行 pytest 验证
5.2 画个样子:它该长啥样
用户提交一个代码文件,Agent 就该像老王接过 PR 一样开工:先读文件、再搜模式,然后分别掏出三本"审查手册"——安全、性能、规范——逐条对照,最后汇成一份结构化报告。要是不放心,还能顺手跑一遍测试。整条流水线画出来是这样的:
%%{init: {'theme':'base','flowchart':{'useMaxWidth':true,'htmlLabels':true}}}%%
graph TD
U["用户提交代码文件"] --> Agent["代码审查 Agent"]
Agent --> R["read_file 读取文件"]
Agent --> G["grep_code 搜索模式"]
R & G --> S1["🛡️ Security Skill SQL注入/XSS/密钥泄露"]
R & G --> S2["⚡ Performance Skill N+1查询/复杂度"]
R & G --> S3["📐 Style Skill 命名/类型/长度"]
S1 & S2 & S3 --> Report["结构化报告 JSON: issues[], score"]
Agent --> Test["run_tests (可选)验证修复"]
classDef uN fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#0d47a1
classDef aN fill:#ede7f6,stroke:#5e35b1,stroke-width:2px,color:#311b92
classDef tN fill:#e0f7fa,stroke:#00acc1,stroke-width:2px,color:#006064
classDef sN fill:#e0f2f1,stroke:#00897b,stroke-width:2px,color:#004d40
class U uN
class Agent aN
class R,G,Test tN
class S1,S2,S3,Report sN
5.3 拆开看:怎么造出来
5.3.1 技术选型
技术点
选型
理由
Agent
create_agent
内置 agent loop(自动多轮)
工具
read_file / grep_code / run_tests
对应的就是真实代码审查工具
Skill
ReviewSkill 基类 + 3 个子类
每个审查维度独立封装,可插拔
模型
Claude Sonnet 4.6
强代码理解能力
5.3.2 关键设计:Skill 模块化——把老王的经验写成 SOP 手册
老王审了十年代码,脑子里攒了一堆"经验法则":看到 password = 就要警惕硬编码、看到循环里有数据库查询就要查 N+1、看到函数超过 50 行就想让人拆……这些经验平时只活在老王脑子里,新人学不到,老王一休假就断了档。
Skill 做的事,就是把这些经验一条条抠出来,写成一本"审查 SOP 手册"。每翻开一页(一个 Skill),Agent 就瞬间变成那个维度的专家。不同于项目一直接把 Prompt 写死在代码里,本章把"审查方法论"抽象为 ReviewSkill 类:每个 Skill 有自己的 name 和 prompt_template,要增加新的审查维度(比如"国际化审查"),只需新增一个子类,已有代码一行都不用动。
💡 顿悟时刻 :Skill 的本质,是"把人的隐性经验,变成 Agent 的显性能力"。新人一翻手册就变专家,老王休假也不怕——因为经验已经长在代码里了。
5.3.3 关键设计:Harness 循环——像老王那样"看一眼、查一下、再回头看"
很多人第一次接触 Agent 都会冒出一个问题:现在的大模型那么强,把整个文件丢给它,让它一次审完不行吗?为什么要绕着圈循环?
我当初也是这么想的。直到我真把一个 500 行的文件丢给模型,让它"全面审查"。它确实吐了一份报告,但读下来你会发现:满纸都是"建议增加注释""变量名可更清晰"这类不痛不痒的话,而那个藏在第 317 行的 SQL 拼接,它压根没提。
为什么?因为"一次性审完"违背了人脑审查的方式。回头看看老王是怎么审一个 PR 的:
先扫一眼 diff——“这段在拼 SQL?嗯,可疑。”
翻出公司的安全规范,对照一下——“确认了,拼接 SQL 是高危。”
还不放心,grep 一下整个仓库——“看看还有没有别的地方也这么写。”
跑一下相关测试——“看会不会挂。”
回头再看一眼最初那段代码——这时候的判断,已经比第一眼深了好几层。
老王从来不是一眼扫完就写报告,他是带着疑问一步步往下挖的。看到第 50 行的 SQL 拼接,他会停下来专门去搜;搜完回来,对第 50 行的判断就变了。审查的质量,来自"看了之后回头再想"的来回,而不是一次性看完。
create_agent 内置的 agent loop,正是逼着模型像人一样,一步、一停、一回头:
读文件 → 发现潜在问题
用 grep 搜索确认 → 定位到具体行
对照 Skill 的审查标准 → 形成报告
如果有修复建议 → 用户可以要求重新审查(开启新一轮循环)
每跑一圈,模型对这份代码的理解就深一层。这就是 Harness 循环存在的理由,也是它反直觉却必不可少的地方。
💡 金句 :一次性审完,得到的是"走马观花";循环着审,得到的才是"老王的眼光"。
5.4 动手写:三层架构完整代码
5.4.1 架构分层总览
层级
文件名
职责
核心类/函数
领域模型层
models.py
定义审查相关的数据结构、状态枚举、Skill 基类
ReviewIssue, ReviewReport, ReviewSkill, Severity
提示词层
prompts.py
集中管理所有系统提示词和审查模板
build_system_prompt(), build_dimension_review_prompt()
工具层
tools.py
封装文件读取、代码搜索、测试运行等工具
read_file, grep_code, run_tests
服务层
service.py
业务逻辑编排、静态规则检查、缓存管理
CodeReviewService
项目入口层
project.py
Agent 构建、项目注册、API 适配
CodeReviewProject
导出层
__init__.py
对外导出、向后兼容
所有 public API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 """P03 代码审查 Agent - 领域模型层""" from __future__ import annotationsimport jsonfrom dataclasses import asdict, dataclass, fieldfrom datetime import datetimefrom enum import Enumfrom typing import Any class Severity (str , Enum): """问题严重程度枚举。""" HIGH = "高危" MEDIUM = "中危" LOW = "低危" class ReviewDimension (str , Enum): """审查维度枚举。""" SECURITY = "security" PERFORMANCE = "performance" STYLE = "style" @dataclass class ReviewIssue : """单个审查问题条目。""" file_path: str line_number: int | None = None severity: Severity = Severity.LOW dimension: ReviewDimension = ReviewDimension.STYLE description: str = "" suggestion: str = "" code_snippet: str = "" def validate (self ) -> list [str ]: """验证字段合法性,返回错误列表。""" errors: list [str ] = [] if not self .file_path: errors.append("file_path 不能为空" ) if not self .description: errors.append("description 不能为空" ) return errors def to_dict (self ) -> dict [str , Any ]: data = asdict(self ) data["severity" ] = self .severity.value data["dimension" ] = self .dimension.value return data @dataclass class ReviewReport : """完整的审查报告。""" target_files: list [str ] = field(default_factory=list ) issues: list [ReviewIssue] = field(default_factory=list ) score: int = 10 reviewed_at: str = field(default_factory=lambda : datetime.now().isoformat()) duration_seconds: float = 0.0 @property def issue_count (self ) -> dict [str , int ]: counts: dict [str , int ] = {"高危" : 0 , "中危" : 0 , "低危" : 0 } for issue in self .issues: counts[issue.severity.value] += 1 return counts def calculate_score (self ) -> int : base = 10 for issue in self .issues: if issue.severity == Severity.HIGH: base -= 2 elif issue.severity == Severity.MEDIUM: base -= 1 return max (1 , min (10 , int (round (base)))) class ReviewSkill : """审查 Skill 基类。""" name: str = "" dimension: ReviewDimension = ReviewDimension.STYLE prompt_template: str = "" class SecurityReviewSkill (ReviewSkill ): """安全审查 Skill。""" name = "security" dimension = ReviewDimension.SECURITY prompt_template = """你是安全审计专家。审查以下代码的安全问题: - SQL 注入(拼接 SQL 字符串) - XSS 漏洞(直接输出用户输入未转义) - 硬编码的密钥/密码/Token - 命令注入(os.system / subprocess 拼接用户输入) 对每个发现的问题标注严重程度,并提供可直接执行的修复代码。""" class PerformanceReviewSkill (ReviewSkill ): """性能审查 Skill。""" name = "performance" dimension = ReviewDimension.PERFORMANCE prompt_template = """你是性能优化专家。审查以下代码的性能问题: - N+1 查询(循环内执行数据库查询) - 不必要的 O(n) 操作(可用 O(1) 替代) - 大对象未释放(内存泄漏风险) - 可并行化的串行操作""" class StyleReviewSkill (ReviewSkill ): """编码规范审查 Skill。""" name = "style" dimension = ReviewDimension.STYLE prompt_template = """你是代码规范专家。审查以下代码的规范问题: - 函数/变量命名是否符合 PEP 8(snake_case) - 缺少类型注解(函数参数和返回值) - 函数过长(超过 50 行建议拆分) - 缺少 docstring(模块、类、公共方法) - 过深的嵌套层级(超过 3 层)""" REVIEW_SKILLS: list [ReviewSkill] = [ SecurityReviewSkill(), PerformanceReviewSkill(), StyleReviewSkill(), ]
核心代码讲解 :
枚举类型安全 :Severity 和 ReviewDimension 用 str 枚举,既保证了类型安全,又能直接序列化进 JSON——老王写报告可不想再手动转换一遍"高危"两个字
数据验证 :ReviewIssue.validate() 给每条问题兜底,确保最终报告里不会出现"光有行号没有描述"这种半拉子条目
可扩展的 Skill 设计 :想加新审查维度?继承 ReviewSkill、填一段 prompt_template 就完事——这正是前文说的"往 SOP 手册里再塞一页"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 """P03 代码审查 Agent - Prompt 层""" from __future__ import annotationsfrom .models import REVIEW_SKILLS, ReviewSkillAGENT_SYSTEM_PROMPT = """你是高级代码审查 Agent,负责对代码变更进行全面审查。 ## 核心职责 1. 读取待审查的文件内容 2. 从安全、性能、规范三个维度逐一审查 3. 输出结构化的审查报告(JSON 格式) ## 输出格式要求 必须输出 JSON 格式的审查报告,结构如下: ```json {{ "target_files": ["path/to/file.py"], "issues": [ {{ "file_path": "path/to/file.py", "line_number": 42, "severity": "高危", "dimension": "security", "description": "问题描述", "suggestion": "修复建议" }} ], "score": 8 }}
审查维度
{review_dimensions}
“”"
def build_system_prompt() -> str:
“”“构建完整的系统提示词,动态注入审查维度。”“”
dimensions_desc = []
for skill in REVIEW_SKILLS:
first_line = skill.prompt_template.split(‘\n’)[0]
dimensions_desc.append(f"- {skill.name.upper()} : {first_line}“)
return AGENT_SYSTEM_PROMPT.format(review_dimensions=”\n".join(dimensions_desc))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 **核心代码讲解**: - **集中管理**:所有提示词收在一个文件里,就像把老王的口头规矩统一抄到一本手册上,便于维护和版本控制 - **动态构建**:`build_system_prompt()` 自动遍历已注册的 Skill,挨个拼出维度说明——新增 Skill 时,提示词会自动跟上,不用手动改 - **格式契约**:白纸黑字写死了 JSON 输出结构,确保下游解析时不会因为格式漂移而炸场 --- ```python """P03 代码审查 Agent - 工具层""" from __future__ import annotationsimport subprocessfrom pathlib import Pathfrom langchain.tools import toolfrom core.logging_conf import get_loggerlogger = get_logger("p03.code_review.tools" ) MAX_FILE_SIZE = 8000 @tool def read_file (file_path: str ) -> str : """读取指定文件的全部内容。""" logger.info("读取文件: %s" , file_path) try : path = Path(file_path) if not path.exists(): return f"文件不存在: {file_path} " content = path.read_text(encoding="utf-8" ) if len (content) > MAX_FILE_SIZE: content = content[:MAX_FILE_SIZE] + f"\n... (已截断至 {MAX_FILE_SIZE} 字符)" return content except Exception as e: logger.exception("读取文件失败: %s" , e) return f"读取文件失败: {type (e).__name__} : {e} " @tool def grep_code (pattern: str , directory: str = "." ) -> str : """在指定目录中搜索代码模式(正则表达式)。""" logger.info("代码搜索: pattern='%s'" , pattern) try : result = subprocess.run( ["grep" , "-rn" , "--include=*.py" , "-n" , pattern, directory], capture_output=True , text=True , timeout=10 , ) if not result.stdout.strip(): return f"未找到匹配 '{pattern} ' 的代码" return result.stdout except Exception as e: logger.exception("搜索失败: %s" , e) return f"搜索失败: {type (e).__name__} : {e} " @tool def run_tests (repo_path: str = "." ) -> str : """在指定目录运行 Python 测试套件。""" logger.info("运行测试: repo_path=%s" , repo_path) try : result = subprocess.run( ["python" , "-m" , "pytest" , "-x" , "--tb=short" , "-q" ], capture_output=True , text=True , timeout=60 , cwd=repo_path, ) return result.stdout or result.stderr except Exception as e: logger.exception("测试运行失败: %s" , e) return f"测试运行失败: {type (e).__name__} : {e} "
核心代码讲解 :
错误降级 :每个工具都裹了 try/except,失败时返回一句友好的人话,而不是让整个 Agent 崩掉——就像老王审到读不了的文件会跳过继续,而不是摔键盘走人
资源保护 :read_file 设了 8000 字截断,防止大文件撑爆上下文窗口;子进程都挂了 timeout,免得一条 grep 把 Agent 卡死到天黑
可观测性 :每次工具调用都打日志,事后能复盘 Agent 这一圈到底干了啥
⚠️ 避坑 :当前 read_file 只检查了"文件存不存在",并没有限制路径范围。要是有人传进 ../../../../etc/passwd 这类路径,Agent 会乖乖读出来。生产环境记得补上 Path.resolve() 加根目录校验,把 Agent 关在自己的项目院子里,别放它出去乱翻。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 """P03 代码审查 Agent - 服务层""" from __future__ import annotationsimport timefrom core.logging_conf import get_loggerfrom .models import REVIEW_SKILLS, ReviewIssue, ReviewReport, Severitylogger = get_logger("p03.code_review.service" ) class CodeReviewService : """代码审查服务。""" def __init__ (self, skills=None ): self .skills = skills or REVIEW_SKILLS logger.info("代码审查服务初始化完成,加载 %d 个审查 Skill" , len (self .skills)) def review_file (self, file_path: str , run_grep: bool = True ) -> ReviewReport: """审查单个文件。""" start_time = time.time() logger.info("开始审查文件: %s" , file_path) report = ReviewReport(target_files=[file_path]) static_issues = self ._static_rule_check(file_path) report.issues.extend(static_issues) report.score = report.calculate_score() report.duration_seconds = time.time() - start_time return report def _static_rule_check (self, file_path: str , content: str ) -> list [ReviewIssue]: """静态规则检查(简单的字符串模式匹配)。""" issues: list [ReviewIssue] = [] lines = content.split("\n" ) for line_no, line in enumerate (lines, 1 ): if "password" in line.lower() and "=" in line and "os.getenv" not in line: issues.append(ReviewIssue( file_path=file_path, line_number=line_no, severity=Severity.HIGH, description="可能存在硬编码密码" , suggestion="使用 os.getenv('PASSWORD') 从环境变量读取" , code_snippet=line.strip(), )) return issues
核心代码讲解 :
职责分层清晰 :Service 层并不直接去调 LLM,而是干那些"不需要脑子"的活儿——静态规则匹配、报告聚合。LLM 该干的循环审查交给 Agent,两边各司其职
可观测性 :完整的执行时间统计加日志记录,审查慢了能一眼看出卡在哪
可配置 :Skill 列表能从外面注入,换一套 Skill 跑测试、做扩展都方便
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 """P03 代码审查 Agent - 项目入口层""" from __future__ import annotationsfrom langchain.agents import create_agentfrom core import BaseProject, build_chat_model, registryfrom core.logging_conf import get_loggerfrom .prompts import build_system_promptfrom .tools import get_available_toolslogger = get_logger("p03.code_review.project" ) class CodeReviewProject (BaseProject ): """代码审查 Agent 项目。""" id = "p03_code_review" name = "代码审查 Agent" description = "自动审查代码安全、性能、规范,输出结构化报告。" capabilities = ["Harness" , "Skill" , "代码审查" ] def build_agent (self ) -> any : """构建代码审查 Agent。""" logger.info("正在构建代码审查 Agent..." ) model = build_chat_model() tools = get_available_tools() system_prompt = build_system_prompt() return create_agent(model=model, tools=tools, system_prompt=system_prompt) registry.register(CodeReviewProject())
核心代码讲解 :
统一接口 :继承 BaseProject,与全书所有项目保持一致的对外 API——换个项目也不用重新学一套用法
装配线模式 :build_agent() 就是一条装配线,依次备好模型、工具、提示词,最后用 create_agent 拧成一台完整的审查机器
自动注册 :导入即注册到全局注册表,调度时一喊就到
5.4.7 init .py - 导出层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 """项目三:代码审查 Agent(生产级 Harness + Skill)""" from __future__ import annotationsfrom .models import ( REVIEW_SKILLS, PerformanceReviewSkill, ReviewIssue, ReviewReport, ReviewSkill, SecurityReviewSkill, Severity, StyleReviewSkill, ) from .prompts import build_system_promptfrom .tools import grep_code, read_file, run_testsfrom .service import CodeReviewServicefrom .project import CodeReviewProjectSYSTEM_PROMPT = build_system_prompt() __all__ = [ "Severity" , "ReviewIssue" , "ReviewReport" , "ReviewSkill" , "SecurityReviewSkill" , "PerformanceReviewSkill" , "StyleReviewSkill" , "REVIEW_SKILLS" , "build_system_prompt" , "SYSTEM_PROMPT" , "read_file" , "grep_code" , "run_tests" , "CodeReviewService" , "CodeReviewProject" , ]
核心代码讲解 :
明确的导出边界 :__all__ 把对外导出的符号列得明明白白,哪些能用、哪些是内部细节,一目了然
向后兼容 :SYSTEM_PROMPT 这个别名留着一截旧代码的命,旧代码不用改也能继续跑
模块化导入 :用户能按需取用——只想要工具写个脚本也行,想要整个 Project 跑全套也行
5.5 跑一跑:它真的行吗
光说不练假把式。下面这几条测试,把工具和 Skill 的关键行为都盯死了:
测试
验证内容
test_read_file
文件读取工具正常工作
test_read_file_not_found
文件不存在时返回友好提示
test_grep_code
代码搜索工具正常工作
test_skills_loaded
三个 Skill 全部加载,名称正确
test_review_simple_file(集成)
Agent 能识别硬编码密码和 SQL 注入
最后那条集成测试是重头戏:真把一段藏着硬编码密码和 SQL 注入的代码喂给 Agent,看它能不能像老王一样把这两条揪出来。
5.6 送上线:让它上班
同第 2 章——继承 BaseProject,自动接入统一 API。不用额外操心发布的事。
5.7 回头看:学到了什么
回头看,这一章 Agent 学会的两样本事,都藏在老王身上:
能力
在本项目中的体现
Harness 循环
create_agent 内置 agent loop,读→搜→审→报告,多轮不间断
Skill 封装
ReviewSkill 基类 + 三个子类,新增审查维度只需加一个新子类
工具集成
read_file / grep_code / run_tests — 对应真实审查工作流
常见坑
审查 Prompt 太泛 ——一句"请审查这个代码"换来的报告,往往又水又没重点。按 Skill 维度把 Prompt 拆开,质量立刻提上来。老王审 PR 也不是一句"看看"完事,他是分门别类地挑。
文件太大 ——read_file 做了 8000 字截断,过大的文件得拆开来分块审,硬塞只会让 Agent"看花眼"。
只跑了一个 Skill ——要是只审了安全、漏了性能和规范,报告就不完整。三个维度都得过一遍,才算真审完。
📌 项目三完成。 Agent 学会了"多轮反复审查"和"把经验打包成 Skill"。下一章我们将攻克 MCP ——标准化的工具接入协议——让 Agent 能连上数据库、API、任意外部系统。
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !