[{"data":1,"prerenderedAt":1250},["ShallowReactive",2],{"post-\u002Fposts\u002Fminicode-source-analysis":3,"all-posts-nav":976},{"id":4,"title":5,"body":6,"categories":959,"date":961,"description":962,"draft":963,"extension":964,"hidden":963,"meta":965,"navigation":161,"path":966,"published":963,"seo":967,"stem":968,"tags":969,"__hash__":975},"posts\u002Fposts\u002Fminicode-source-analysis.md","MiniCode 源码解析：用 5000 行 TypeScript 实现一个 AI 编程助手",{"type":7,"value":8,"toc":938},"minimark",[9,22,26,36,44,47,56,59,262,265,287,298,301,390,393,513,519,526,529,535,538,558,561,568,571,578,584,587,590,597,600,606,609,639,646,652,658,661,664,667,708,711,714,719,722,737,740,745,748,759,762,767,770,775,778,783,786,789,899,902,934],[10,11,12,13,17,18,21],"p",{},"MiniCode 是一个轻量级终端 AI 编程助手，类 Claude Code 工作流，181 ⭐。整个核心只有 5000 行 TypeScript，依赖极简（只有 ",[14,15,16],"code",{},"diff"," 和 ",[14,19,20],{},"zod"," 两个运行时依赖），非常适合学习 AI Agent 的架构设计。这篇文章从源码角度拆解它的实现，作为面试准备。",[23,24,25],"h2",{"id":25},"整体架构",[27,28,33],"pre",{"className":29,"code":31,"language":32},[30],"language-text","用户输入\n   ↓\nindex.ts（入口：初始化配置、工具注册、权限管理）\n   ↓\nagent-loop.ts（核心循环：发送消息 → 解析工具调用 → 执行工具 → 继续）\n   ↙              ↘\ntool.ts           tty-app.ts\n（工具注册表）      （终端 UI）\n   ↓\ntools\u002F（内置工具：读写文件、执行命令、搜索、网络请求）\nmcp.ts（外部 MCP 工具服务器）\n","text",[14,34,31],{"__ignoreMap":35},"",[10,37,38,39,43],{},"这是标准的 ",[40,41,42],"strong",{},"ReAct（Reasoning + Acting）"," 模式：模型思考 → 调用工具 → 观察结果 → 继续思考，循环直到任务完成。",[23,45,46],{"id":46},"核心模块拆解",[48,49,51,52,55],"h3",{"id":50},"_1-agent-loopsrcagent-loopts","1. Agent Loop（",[14,53,54],{},"src\u002Fagent-loop.ts","）",[10,57,58],{},"这是整个项目最核心的文件，实现了 LLM 的工具调用循环：",[27,60,64],{"className":61,"code":62,"language":63,"meta":35,"style":35},"language-typescript shiki shiki-themes github-dark-dimmed github-light","\u002F\u002F 伪代码，展示核心逻辑\nasync function agentLoop(messages, tools, model) {\n  while (true) {\n    \u002F\u002F 1. 调用模型\n    const response = await model.call(messages, tools)\n\n    \u002F\u002F 2. 如果模型只返回文本（没有工具调用），结束循环\n    if (!response.hasToolCalls) {\n      return response\n    }\n\n    \u002F\u002F 3. 执行工具调用\n    const toolResults = await executeTools(response.toolCalls)\n\n    \u002F\u002F 4. 把工具结果加入消息历史，继续循环\n    messages.push(response, toolResults)\n  }\n}\n","typescript",[14,65,66,75,111,126,132,156,163,169,183,192,198,203,209,227,232,238,250,256],{"__ignoreMap":35},[67,68,71],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sgHix","\u002F\u002F 伪代码，展示核心逻辑\n",[67,76,78,82,85,89,93,97,100,103,105,108],{"class":69,"line":77},2,[67,79,81],{"class":80},"s6PUj","async",[67,83,84],{"class":80}," function",[67,86,88],{"class":87},"saVmf"," agentLoop",[67,90,92],{"class":91},"ssh_m","(",[67,94,96],{"class":95},"sNjOc","messages",[67,98,99],{"class":91},", ",[67,101,102],{"class":95},"tools",[67,104,99],{"class":91},[67,106,107],{"class":95},"model",[67,109,110],{"class":91},") {\n",[67,112,114,117,120,124],{"class":69,"line":113},3,[67,115,116],{"class":80},"  while",[67,118,119],{"class":91}," (",[67,121,123],{"class":122},"swcJU","true",[67,125,110],{"class":91},[67,127,129],{"class":69,"line":128},4,[67,130,131],{"class":73},"    \u002F\u002F 1. 调用模型\n",[67,133,135,138,141,144,147,150,153],{"class":69,"line":134},5,[67,136,137],{"class":80},"    const",[67,139,140],{"class":122}," response",[67,142,143],{"class":80}," =",[67,145,146],{"class":80}," await",[67,148,149],{"class":91}," model.",[67,151,152],{"class":87},"call",[67,154,155],{"class":91},"(messages, tools)\n",[67,157,159],{"class":69,"line":158},6,[67,160,162],{"emptyLinePlaceholder":161},true,"\n",[67,164,166],{"class":69,"line":165},7,[67,167,168],{"class":73},"    \u002F\u002F 2. 如果模型只返回文本（没有工具调用），结束循环\n",[67,170,172,175,177,180],{"class":69,"line":171},8,[67,173,174],{"class":80},"    if",[67,176,119],{"class":91},[67,178,179],{"class":80},"!",[67,181,182],{"class":91},"response.hasToolCalls) {\n",[67,184,186,189],{"class":69,"line":185},9,[67,187,188],{"class":80},"      return",[67,190,191],{"class":91}," response\n",[67,193,195],{"class":69,"line":194},10,[67,196,197],{"class":91},"    }\n",[67,199,201],{"class":69,"line":200},11,[67,202,162],{"emptyLinePlaceholder":161},[67,204,206],{"class":69,"line":205},12,[67,207,208],{"class":73},"    \u002F\u002F 3. 执行工具调用\n",[67,210,212,214,217,219,221,224],{"class":69,"line":211},13,[67,213,137],{"class":80},[67,215,216],{"class":122}," toolResults",[67,218,143],{"class":80},[67,220,146],{"class":80},[67,222,223],{"class":87}," executeTools",[67,225,226],{"class":91},"(response.toolCalls)\n",[67,228,230],{"class":69,"line":229},14,[67,231,162],{"emptyLinePlaceholder":161},[67,233,235],{"class":69,"line":234},15,[67,236,237],{"class":73},"    \u002F\u002F 4. 把工具结果加入消息历史，继续循环\n",[67,239,241,244,247],{"class":69,"line":240},16,[67,242,243],{"class":91},"    messages.",[67,245,246],{"class":87},"push",[67,248,249],{"class":91},"(response, toolResults)\n",[67,251,253],{"class":69,"line":252},17,[67,254,255],{"class":91},"  }\n",[67,257,259],{"class":69,"line":258},18,[67,260,261],{"class":91},"}\n",[10,263,264],{},"关键细节：",[266,267,268,275,281],"ul",{},[269,270,271,274],"li",{},[40,272,273],{},"重试逻辑","：模型返回空响应时自动重试",[269,276,277,280],{},[40,278,279],{},"权限检查","：每次工具调用前先过权限管理器",[269,282,283,286],{},[40,284,285],{},"错误处理","：工具执行失败时把错误信息反馈给模型，让它自行纠正",[48,288,290,291,294,295,55],{"id":289},"_2-工具系统srctoolts-srctools","2. 工具系统（",[14,292,293],{},"src\u002Ftool.ts"," + ",[14,296,297],{},"src\u002Ftools\u002F",[10,299,300],{},"所有工具（内置 + MCP 外部工具）遵循同一个接口：",[27,302,304],{"className":61,"code":303,"language":63,"meta":35,"style":35},"interface Tool {\n  name: string\n  description: string\n  parameters: ZodSchema  \u002F\u002F 用 Zod 做运行时参数校验\n  execute: (params, context) => Promise\u003CToolResult>\n}\n",[14,305,306,318,329,338,351,386],{"__ignoreMap":35},[67,307,308,311,315],{"class":69,"line":70},[67,309,310],{"class":80},"interface",[67,312,314],{"class":313},"sqRhv"," Tool",[67,316,317],{"class":91}," {\n",[67,319,320,323,326],{"class":69,"line":77},[67,321,322],{"class":95},"  name",[67,324,325],{"class":80},":",[67,327,328],{"class":122}," string\n",[67,330,331,334,336],{"class":69,"line":113},[67,332,333],{"class":95},"  description",[67,335,325],{"class":80},[67,337,328],{"class":122},[67,339,340,343,345,348],{"class":69,"line":128},[67,341,342],{"class":95},"  parameters",[67,344,325],{"class":80},[67,346,347],{"class":313}," ZodSchema",[67,349,350],{"class":73},"  \u002F\u002F 用 Zod 做运行时参数校验\n",[67,352,353,356,358,360,363,365,368,371,374,377,380,383],{"class":69,"line":134},[67,354,355],{"class":87},"  execute",[67,357,325],{"class":80},[67,359,119],{"class":91},[67,361,362],{"class":95},"params",[67,364,99],{"class":91},[67,366,367],{"class":95},"context",[67,369,370],{"class":91},") ",[67,372,373],{"class":80},"=>",[67,375,376],{"class":313}," Promise",[67,378,379],{"class":91},"\u003C",[67,381,382],{"class":313},"ToolResult",[67,384,385],{"class":91},">\n",[67,387,388],{"class":69,"line":158},[67,389,261],{"class":91},[10,391,392],{},"内置工具清单：",[394,395,396,409],"table",{},[397,398,399],"thead",{},[400,401,402,406],"tr",{},[403,404,405],"th",{},"工具",[403,407,408],{},"功能",[410,411,412,423,433,443,453,463,473,483,493,503],"tbody",{},[400,413,414,420],{},[415,416,417],"td",{},[14,418,419],{},"read_file",[415,421,422],{},"读取文件内容",[400,424,425,430],{},[415,426,427],{},[14,428,429],{},"write_file",[415,431,432],{},"写入文件（需权限审批）",[400,434,435,440],{},[415,436,437],{},[14,438,439],{},"edit_file",[415,441,442],{},"局部编辑（生成 diff 预览）",[400,444,445,450],{},[415,446,447],{},[14,448,449],{},"list_files",[415,451,452],{},"列出目录文件",[400,454,455,460],{},[415,456,457],{},[14,458,459],{},"grep_files",[415,461,462],{},"正则搜索文件内容",[400,464,465,470],{},[415,466,467],{},[14,468,469],{},"run_command",[415,471,472],{},"执行 Shell 命令（需权限审批）",[400,474,475,480],{},[415,476,477],{},[14,478,479],{},"web_fetch",[415,481,482],{},"抓取网页内容",[400,484,485,490],{},[415,486,487],{},[14,488,489],{},"web_search",[415,491,492],{},"网络搜索",[400,494,495,500],{},[415,496,497],{},[14,498,499],{},"ask_user",[415,501,502],{},"向用户提问",[400,504,505,510],{},[415,506,507],{},[14,508,509],{},"load_skill",[415,511,512],{},"加载本地 Skill 文件",[10,514,515,518],{},[40,516,517],{},"Zod 的作用","：模型返回的工具参数是 JSON，Zod 在运行时校验参数类型，防止模型幻觉导致的非法参数进入执行层。",[48,520,522,523,55],{"id":521},"_3-权限系统srcpermissionsts","3. 权限系统（",[14,524,525],{},"src\u002Fpermissions.ts",[10,527,528],{},"这是 AI Agent 安全性的核心设计。所有\"危险操作\"（写文件、执行命令）都需要用户审批：",[27,530,533],{"className":531,"code":532,"language":32},[30],"模型想执行 run_command(\"rm -rf \u002Ftmp\u002Fxxx\")\n         ↓\n权限管理器拦截，展示给用户：\n  ┌─────────────────────────────┐\n  │ Allow: rm -rf \u002Ftmp\u002Fxxx ?    │\n  │ [Y] Yes  [N] No  [A] Always │\n  └─────────────────────────────┘\n         ↓\n用户选择 → 执行或拒绝（拒绝时把原因反馈给模型）\n",[14,534,532],{"__ignoreMap":35},[10,536,537],{},"审批模式：",[266,539,540,546,552],{},[269,541,542,545],{},[40,543,544],{},"Allow this turn"," — 本次会话允许",[269,547,548,551],{},[40,549,550],{},"Allow always"," — 加入白名单，后续不再询问",[269,553,554,557],{},[40,555,556],{},"Reject with guidance"," — 拒绝并告诉模型为什么，让它换个方案",[10,559,560],{},"文件修改会先生成 unified diff 预览，用户看到具体改了什么再决定是否允许。",[48,562,564,565,55],{"id":563},"_4-mcp-集成srcmcpts","4. MCP 集成（",[14,566,567],{},"src\u002Fmcp.ts",[10,569,570],{},"MCP（Model Context Protocol）是 Anthropic 定义的工具服务器协议，允许外部进程提供工具给模型使用。",[10,572,573,574,577],{},"MiniCode 的 MCP 实现亮点是",[40,575,576],{},"自动协商帧协议","：",[27,579,582],{"className":580,"code":581,"language":32},[30],"启动 MCP 服务器进程\n         ↓\n尝试标准 Content-Length 帧格式（MCP 规范）\n         ↓ 失败\n回退到 newline-JSON 格式（轻量级）\n         ↓ 失败\n尝试 HTTP streaming\n",[14,583,581],{"__ignoreMap":35},[10,585,586],{},"这样可以兼容不严格遵循 MCP 规范的服务器，实用性更强。",[10,588,589],{},"外部 MCP 工具被包装成和内置工具相同的接口，Agent Loop 不需要区分工具来源。",[48,591,593,594,55],{"id":592},"_5-终端-uisrctty-appts","5. 终端 UI（",[14,595,596],{},"src\u002Ftty-app.ts",[10,598,599],{},"这是代码量最大的文件（39KB），实现了一个全屏 TUI（Terminal User Interface）：",[27,601,604],{"className":602,"code":603,"language":32},[30],"┌─────────────────────────────────────────┐\n│ 对话历史（用户消息 \u002F 模型回复 \u002F 工具调用）  │\n│                                         │\n│ > 用户: 帮我重构这个函数                  │\n│ ✓ read_file: src\u002Futils.ts               │\n│ ✓ edit_file: src\u002Futils.ts (diff 预览)   │\n│ ◎ 模型: 已完成重构，主要改动是...          │\n│                                         │\n├─────────────────────────────────────────┤\n│ > 输入框                    [tokens: 1.2k]│\n└─────────────────────────────────────────┘\n",[14,605,603],{"__ignoreMap":35},[10,607,608],{},"技术细节：",[266,610,611,614,620],{},[269,612,613],{},"直接操作 TTY 转义序列（不依赖 ncurses 或 blessed）",[269,615,616,617,55],{},"输入历史持久化（",[14,618,619],{},"src\u002Fhistory.ts",[269,621,622,623,626,627,626,630,626,633,626,636],{},"Slash 命令：",[14,624,625],{},"\u002Fhelp","、",[14,628,629],{},"\u002Ftools",[14,631,632],{},"\u002Fskills",[14,634,635],{},"\u002Fmcp",[14,637,638],{},"\u002Fmodel",[48,640,642,643,55],{"id":641},"_6-skills-系统srcskillsts","6. Skills 系统（",[14,644,645],{},"src\u002Fskills.ts",[10,647,648,649,651],{},"Skills 是存储在本地的 Markdown 文件，模型可以通过 ",[14,650,509],{}," 工具加载：",[27,653,656],{"className":654,"code":655,"language":32},[30],"发现路径（优先级从高到低）：\n.\u002F.mini-code\u002Fskills\u002F\u003Cname>\u002FSKILL.md   # 项目级\n~\u002F.mini-code\u002Fskills\u002F\u003Cname>\u002FSKILL.md   # 用户级\n.\u002F.claude\u002Fskills\u002F\u003Cname>\u002FSKILL.md      # 兼容 Claude Code\n~\u002F.claude\u002Fskills\u002F\u003Cname>\u002FSKILL.md\n",[14,657,655],{"__ignoreMap":35},[10,659,660],{},"这个设计让用户可以把常用的工作流（比如\"提交代码\"、\"写测试\"）封装成 Skill，模型按需加载，不需要每次都在 System Prompt 里塞满指令。",[23,662,663],{"id":663},"依赖极简的设计哲学",[10,665,666],{},"整个项目运行时只依赖两个包：",[394,668,669,682],{},[397,670,671],{},[400,672,673,676,679],{},[403,674,675],{},"包",[403,677,678],{},"用途",[403,680,681],{},"为什么不自己实现",[410,683,684,696],{},[400,685,686,690,693],{},[415,687,688],{},[14,689,16],{},[415,691,692],{},"生成 unified diff",[415,694,695],{},"diff 算法（Myers diff）实现复杂，有成熟库直接用",[400,697,698,702,705],{},[415,699,700],{},[14,701,20],{},[415,703,704],{},"运行时 Schema 校验",[415,706,707],{},"工具参数校验是安全关键路径，用成熟库更可靠",[10,709,710],{},"其他所有功能（HTTP 请求、文件操作、终端控制）全部用 Node.js 内置模块实现。这让整个项目安装极快，没有依赖地狱。",[23,712,713],{"id":713},"面试常见问题",[10,715,716],{},[40,717,718],{},"Q：什么是 ReAct 模式？",[10,720,721],{},"ReAct = Reasoning + Acting。模型不是一次性给出答案，而是交替进行\"思考\"和\"行动\"：",[723,724,725,728,731,734],"ol",{},[269,726,727],{},"思考：分析当前状态，决定下一步做什么",[269,729,730],{},"行动：调用工具获取信息或执行操作",[269,732,733],{},"观察：把工具结果加入上下文",[269,735,736],{},"重复，直到任务完成",[10,738,739],{},"相比单次推理，ReAct 能处理需要多步骤、需要外部信息的复杂任务。",[10,741,742],{},[40,743,744],{},"Q：为什么 AI Agent 需要权限系统？",[10,746,747],{},"LLM 会产生幻觉，可能调用错误的工具参数（比如删错文件）。权限系统在执行层做最后一道防线：",[266,749,750,753,756],{},[269,751,752],{},"危险操作（写文件、执行命令）必须人工确认",[269,754,755],{},"展示 diff 让用户看到具体改动",[269,757,758],{},"拒绝时把原因反馈给模型，让它自我纠正",[10,760,761],{},"这是\"Human in the loop\"设计原则的体现。",[10,763,764],{},[40,765,766],{},"Q：MCP 协议是什么？",[10,768,769],{},"Model Context Protocol，Anthropic 提出的开放标准，定义了 AI 模型和外部工具服务器之间的通信协议。类似 LSP（Language Server Protocol）之于编辑器，MCP 让工具服务器和 AI 客户端解耦，任何支持 MCP 的工具都能被任何支持 MCP 的模型使用。",[10,771,772],{},[40,773,774],{},"Q：Zod 在这里解决什么问题？",[10,776,777],{},"模型返回的工具调用参数是 JSON 字符串，TypeScript 的类型系统在运行时不起作用。Zod 在运行时校验参数结构，如果模型返回了错误类型的参数（比如把数字传成了字符串），Zod 会抛出详细的错误信息，可以反馈给模型让它重试，而不是让错误参数进入执行层导致不可预期的行为。",[10,779,780],{},[40,781,782],{},"Q：为什么只用两个运行时依赖？",[10,784,785],{},"依赖越少，安全风险越低（供应链攻击），安装越快，代码越容易理解。Node.js 内置模块已经足够实现 HTTP、文件操作、进程管理。只在\"自己实现成本高且风险大\"的地方（diff 算法、Schema 校验）引入外部依赖，这是工程上的克制。",[23,787,788],{"id":788},"如何本地运行",[27,790,794],{"className":791,"code":792,"language":793,"meta":35,"style":35},"language-bash shiki shiki-themes github-dark-dimmed github-light","git clone https:\u002F\u002Fgithub.com\u002FLiuMengxuan04\u002FMiniCode\ncd MiniCode\nnpm install\nnpm run install-local   # 安装到 ~\u002F.local\u002Fbin\u002Fminicode\n\n# 设置 API Key\nexport ANTHROPIC_API_KEY=your_key\n\nminicode                # 启动交互模式\n\n# 离线 demo 模式（不需要 API Key）\nMINI_CODE_MODEL_MODE=mock npm run dev\n","bash",[14,795,796,808,816,824,837,841,846,860,864,872,876,881],{"__ignoreMap":35},[67,797,798,801,805],{"class":69,"line":70},[67,799,800],{"class":313},"git",[67,802,804],{"class":803},"sXfbr"," clone",[67,806,807],{"class":803}," https:\u002F\u002Fgithub.com\u002FLiuMengxuan04\u002FMiniCode\n",[67,809,810,813],{"class":69,"line":77},[67,811,812],{"class":122},"cd",[67,814,815],{"class":803}," MiniCode\n",[67,817,818,821],{"class":69,"line":113},[67,819,820],{"class":313},"npm",[67,822,823],{"class":803}," install\n",[67,825,826,828,831,834],{"class":69,"line":128},[67,827,820],{"class":313},[67,829,830],{"class":803}," run",[67,832,833],{"class":803}," install-local",[67,835,836],{"class":73},"   # 安装到 ~\u002F.local\u002Fbin\u002Fminicode\n",[67,838,839],{"class":69,"line":134},[67,840,162],{"emptyLinePlaceholder":161},[67,842,843],{"class":69,"line":158},[67,844,845],{"class":73},"# 设置 API Key\n",[67,847,848,851,854,857],{"class":69,"line":165},[67,849,850],{"class":80},"export",[67,852,853],{"class":91}," ANTHROPIC_API_KEY",[67,855,856],{"class":80},"=",[67,858,859],{"class":91},"your_key\n",[67,861,862],{"class":69,"line":171},[67,863,162],{"emptyLinePlaceholder":161},[67,865,866,869],{"class":69,"line":185},[67,867,868],{"class":313},"minicode",[67,870,871],{"class":73},"                # 启动交互模式\n",[67,873,874],{"class":69,"line":194},[67,875,162],{"emptyLinePlaceholder":161},[67,877,878],{"class":69,"line":200},[67,879,880],{"class":73},"# 离线 demo 模式（不需要 API Key）\n",[67,882,883,886,888,891,894,896],{"class":69,"line":205},[67,884,885],{"class":91},"MINI_CODE_MODEL_MODE",[67,887,856],{"class":80},[67,889,890],{"class":803},"mock",[67,892,893],{"class":313}," npm",[67,895,830],{"class":803},[67,897,898],{"class":803}," dev\n",[23,900,901],{"id":901},"值得学习的设计",[723,903,904,910,916,922,928],{},[269,905,906,909],{},[40,907,908],{},"统一工具接口","：内置工具和 MCP 外部工具用同一套接口，Agent Loop 不感知来源",[269,911,912,915],{},[40,913,914],{},"权限前置","：危险操作在执行前拦截，而不是执行后补救",[269,917,918,921],{},[40,919,920],{},"错误反馈给模型","：工具失败不直接报错，而是把错误信息加入消息历史让模型自行纠正",[269,923,924,927],{},[40,925,926],{},"Skills 本地优先","：不依赖云端 marketplace，项目级和用户级 Skill 都支持",[269,929,930,933],{},[40,931,932],{},"协议自动协商","：MCP 帧格式自动降级，兼容性更好",[935,936,937],"style",{},"html pre.shiki code .sqRhv, html code.shiki .sqRhv{--shiki-default:#F69D50;--shiki-light:#6F42C1}html pre.shiki code .sXfbr, html code.shiki .sXfbr{--shiki-default:#96D0FF;--shiki-light:#032F62}html pre.shiki code .swcJU, html code.shiki .swcJU{--shiki-default:#6CB6FF;--shiki-light:#005CC5}html pre.shiki code .sgHix, html code.shiki .sgHix{--shiki-default:#768390;--shiki-light:#6A737D}html pre.shiki code .s6PUj, html code.shiki .s6PUj{--shiki-default:#F47067;--shiki-light:#D73A49}html pre.shiki code .ssh_m, html code.shiki .ssh_m{--shiki-default:#ADBAC7;--shiki-light:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .saVmf, html code.shiki .saVmf{--shiki-default:#DCBDFB;--shiki-light:#6F42C1}html pre.shiki code .sNjOc, html code.shiki .sNjOc{--shiki-default:#F69D50;--shiki-light:#E36209}",{"title":35,"searchDepth":77,"depth":113,"links":939},[940,941,955,956,957,958],{"id":25,"depth":77,"text":25},{"id":46,"depth":77,"text":46,"children":942},[943,945,947,949,951,953],{"id":50,"depth":113,"text":944},"1. Agent Loop（src\u002Fagent-loop.ts）",{"id":289,"depth":113,"text":946},"2. 工具系统（src\u002Ftool.ts + src\u002Ftools\u002F）",{"id":521,"depth":113,"text":948},"3. 权限系统（src\u002Fpermissions.ts）",{"id":563,"depth":113,"text":950},"4. MCP 集成（src\u002Fmcp.ts）",{"id":592,"depth":113,"text":952},"5. 终端 UI（src\u002Ftty-app.ts）",{"id":641,"depth":113,"text":954},"6. Skills 系统（src\u002Fskills.ts）",{"id":663,"depth":77,"text":663},{"id":713,"depth":77,"text":713},{"id":788,"depth":77,"text":788},{"id":901,"depth":77,"text":901},[960],"技术","2026-04-06","MiniCode 是一个轻量级终端 AI 编程助手，类 Claude Code 工作流，181 ⭐。整个核心只有 5000 行 TypeScript，依赖极简（只有 diff 和 zod 两个运行时依赖），非常适合学习 AI Agent 的架构设计。这篇文章从源码角度拆解它的实现，作为面试准备。",false,"md",{},"\u002Fposts\u002Fminicode-source-analysis",{"title":5,"description":962},"posts\u002Fminicode-source-analysis",[970,971,972,973,974],"TypeScript","CLI","LLM","源码分析","面试","MS582Wi30ox8rVqnQqBBSs3hiYvuhJ2uXhyJpsaRh-o",[977,990,1001,1007,1018,1027,1036,1046,1055,1064,1074,1086,1099,1111,1119,1129,1141,1152,1162,1170,1181,1187,1193,1199,1207,1216,1223,1226,1234,1241],{"slug":978,"path":979,"title":980,"date":981,"tags":982,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":185},"multimodal-rag-from-scratch","\u002Fposts\u002Fmultimodal-rag-from-scratch","从零实现多模态 RAG：BM25、Dense 检索、RRF 融合、MMR 重排全部手写","2026-06-30 18:00:00",[983,984,985,986,987,988,989],"RAG","多模态","AI Infra","BM25","向量检索","混合检索","实习求职",{"slug":991,"path":992,"title":993,"date":994,"tags":995,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":200},"mini-llm-engine-deep-dive","\u002Fposts\u002Fmini-llm-engine-deep-dive","讲透 mini-llm-engine：从显存碎片到六大推理优化","2026-06-30 14:00:00",[972,985,996,997,998,999,1000,989],"vLLM","PagedAttention","KV Cache","推理优化","投机解码",{"slug":1002,"path":1003,"title":1004,"date":1005,"tags":1006,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":194},"mini-llm-engine-from-scratch","\u002Fposts\u002Fmini-llm-engine-from-scratch","从零实现 LLM 推理引擎：深挖 vLLM 的六大核心优化","2026-06-30 10:00:00",[972,985,996,997,999,1000,989],{"slug":1008,"path":1009,"title":1010,"date":1011,"tags":1012,"description":1017,"draft":963,"hidden":963,"published":161,"readingTime":258},"bytedance-recommendation-architecture-intern-interview","\u002Fposts\u002Fbytedance-recommendation-architecture-intern-interview","字节推荐架构实习生 Data 面试准备：推荐系统、实时特征与高并发八股","2026-06-09",[974,1013,1014,1015,1016],"推荐系统","后端架构","实时计算","字节跳动","面向字节跳动推荐架构团队实习岗位的八股准备清单，覆盖推荐系统链路、实时数据、特征服务、高并发后端、分布式系统与项目包装。",{"slug":1019,"path":1020,"title":1021,"date":1011,"tags":1022,"description":1026,"draft":963,"hidden":963,"published":161,"readingTime":205},"high-concurrency-rate-limiting-algorithms","\u002Fposts\u002Fhigh-concurrency-rate-limiting-algorithms","高并发限流算法：固定窗口、滑动窗口、漏桶与令牌桶",[1023,1024,1014,1025,974],"高并发","限流","系统设计","面试和工程都常见的限流算法总结，讲清楚固定窗口、滑动窗口、漏桶、令牌桶、并发数限制以及分布式限流如何落地。",{"slug":1028,"path":1029,"title":1030,"date":1011,"tags":1031,"description":1035,"draft":963,"hidden":963,"published":161,"readingTime":171},"kafka-producer-broker-consumer","\u002Fposts\u002Fkafka-producer-broker-consumer","Kafka 入门：生产者、Broker、消费者和“消费”到底是什么意思",[1032,1033,1034,974,1013],"Kafka","消息队列","后端","用推荐系统里的用户行为日志为例，讲清楚 Kafka 的作用、Producer、Broker、Consumer、Topic、Partition、Offset 和消费语义。",{"slug":1037,"path":1038,"title":1039,"date":1011,"tags":1040,"description":1045,"draft":963,"hidden":963,"published":161,"readingTime":158},"leetcode-lru-merge-k-reverse-list","\u002Fposts\u002Fleetcode-lru-merge-k-reverse-list","链表与缓存高频题：LRU Cache、合并 K 个有序链表、反转链表",[1041,1042,1043,1044,974],"算法","链表","LRU","LeetCode","面试高频算法题速记，整理 LRU Cache、合并 K 个有序链表、反转链表的核心思路、复杂度和 C++ 代码。",{"slug":1047,"path":1048,"title":1049,"date":1050,"tags":1051,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":240},"meddococr-interpreter-source-analysis","\u002Fposts\u002Fmeddococr-interpreter-source-analysis","MedDocOCR-Interpreter 源码导读：医疗文档 OCR、结构化抽取与报告解读原型","2026-05-22 10:30:00",[1052,984,1053,983,1054,973],"OCR","医疗 AI","Python",{"slug":1056,"path":1057,"title":1058,"date":1059,"tags":1060,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":194},"cet6-writing-model-essays","\u002Fposts\u002Fcet6-writing-model-essays","六级写作范文背诵包：10 个高频话题","2026-05-20 09:00:00",[1061,1062,1063],"English","CET6","Writing",{"slug":1065,"path":1066,"title":1067,"date":1068,"tags":1069,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":1073},"claude-code-context-management","\u002Fposts\u002Fclaude-code-context-management","Claude Code 上下文管理机制：从 Microcompact 到 Auto Compact","2026-05-19 10:00:00",[1070,1071,972,985,1072],"Claude Code","Agent","上下文工程",27,{"slug":1075,"path":1076,"title":1077,"date":1078,"tags":1079,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":1085},"nanotron-llm-pretraining-framework-analysis","\u002Fposts\u002Fnanotron-llm-pretraining-framework-analysis","Nanotron 项目详解：Hugging Face 的大模型预训练框架怎么做分布式训练","2026-05-10 12:10:00",[972,1080,1081,1082,1083,985,1084],"大模型训练","分布式训练","Nanotron","Hugging Face","PyTorch",19,{"slug":1087,"path":1088,"title":1089,"date":1090,"tags":1091,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":1098},"gofoundry-go-backend-foundation-framework","\u002Fposts\u002Fgofoundry-go-backend-foundation-framework","GoFoundry 项目详解：基于 Go 的后端基础框架套件设计","2026-05-10 11:20:00",[1092,1093,1094,1095,1096,1033,1097],"Go","后端框架","ORM","分布式缓存","分布式锁","项目架构",25,{"slug":1100,"path":1101,"title":1102,"date":1103,"tags":1104,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":1073},"cloudvault-go-cloud-storage-system","\u002Fposts\u002Fcloudvault-go-cloud-storage-system","CloudVault 项目详解：基于 Go 的云端存储与网盘系统架构设计","2026-05-10 10:30:00",[1092,1105,1106,1107,1097,1108,1109,1110],"云存储","网盘系统","分布式系统","Redis","RabbitMQ","Elasticsearch",{"slug":1112,"path":1113,"title":1114,"date":1115,"tags":1116,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":1118},"openclaw-source-code-analysis","\u002Fposts\u002Fopenclaw-source-code-analysis","OpenClaw 源码导读：个人 AI 助手的网关、通道、插件与运行时架构","2026-05-08 16:30:00",[1117,1071,985,970,973],"OpenClaw",20,{"slug":1120,"path":1121,"title":1122,"date":1123,"tags":1124,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":194},"flow-matching-generative-models","\u002Fposts\u002Fflow-matching-generative-models","Flow Matching：从噪声到数据的连续流生成模型","2026-05-07 00:00:00",[1125,1126,1127,1128],"生成模型","Diffusion","Flow Matching","深度学习",{"slug":1130,"path":1131,"title":1132,"date":1133,"tags":1134,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":234},"database-ai-week4","\u002Fposts\u002Fdatabase-ai-week4","Week 4：数据库速成——从 Storage、Index、Query Optimization 到 Vector DB 与 RAG","2026-05-05 12:00:00",[1135,1136,1137,983,1138,1139,1140],"数据库","CMU 15-445","Vector DB","LLM Memory","Query Optimization","Caching",{"slug":1142,"path":1143,"title":1144,"date":1145,"tags":1146,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":240},"distributed-systems-week3","\u002Fposts\u002Fdistributed-systems-week3","Week 3：分布式系统速成——MapReduce、Raft、容错与 Distributed KV Store","2026-05-05 11:00:00",[1107,1147,1148,1149,1150,1151,1071],"MIT 6.824","MapReduce","Raft","KV Store","Ray",{"slug":1153,"path":1154,"title":1155,"date":1156,"tags":1157,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":234},"gpu-inference-acceleration-week2","\u002Fposts\u002Fgpu-inference-acceleration-week2","Week 2：GPU 与推理加速——从 Kernel、算子融合到 LLM Serving","2026-05-05 10:00:00",[1128,1158,1159,972,1160,996,1161],"GPU","推理加速","CMU 10-414","TensorRT",{"slug":1163,"path":1164,"title":1165,"date":1166,"tags":1167,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":258},"dl-framework-autograd-mini","\u002Fposts\u002Fdl-framework-autograd-mini","Week 1：DL 框架与 Autograd——从计算图、反向传播到 Mini Autograd 实现","2026-05-05 09:00:00",[1128,1168,1084,1160,1169],"Autograd","Mini Framework",{"slug":1171,"path":1172,"title":1173,"date":1174,"tags":1175,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":205},"lock-free-concurrency-notes","\u002Fposts\u002Flock-free-concurrency-notes","无锁并发入门：从 CAS 到 Atomic Ring Buffer","2026-04-25",[1176,1177,1178,1179,1180],"C++","并发","无锁编程","性能优化","量化开发",{"slug":1182,"path":1183,"title":1184,"date":1185,"tags":1186,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":134},"agent-memory","\u002Fposts\u002Fagent-memory","Agent 对话记忆化：从原理到实现","2026-04-24",[972,1071,983,974],{"slug":1188,"path":1189,"title":1190,"date":1185,"tags":1191,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":158},"llm-context-compression","\u002Fposts\u002Fllm-context-compression","LLM 上下文五层压缩机制详解",[972,1071,1192,974],"上下文压缩",{"slug":1194,"path":1195,"title":1196,"date":1197,"tags":1198,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":185},"cpp-concurrency-basics","\u002Fposts\u002Fcpp-concurrency-basics","C++ 并发编程入门：从数据竞争到线程池","2026-04-15",[1176,1177,974,1180],{"slug":1200,"path":1201,"title":1202,"date":1203,"tags":1204,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":70},"travel-in-shenzhen","\u002Fposts\u002Ftravel-in-shenzhen","XCPC 深圳游记","2026-04-13",[1205,1176,1206],"XCPC","比赛",{"slug":1208,"path":1209,"title":1210,"date":1211,"tags":1212,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":165},"backend-stack-deep-dive","\u002Fposts\u002Fbackend-stack-deep-dive","后端五件套：FastAPI \u002F Node.js \u002F SQLAlchemy async \u002F PostgreSQL \u002F Docker 面试速通","2026-04-07",[1034,1213,1214,1215,974],"FastAPI","PostgreSQL","Docker",{"slug":1217,"path":1218,"title":1219,"date":961,"tags":1220,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":158},"deepscientist-tech-stack","\u002Fposts\u002Fdeepscientist-tech-stack","DeepScientist 技术栈全解析：一个 AI 科研平台的架构设计",[1221,1213,1222,1214,974],"全栈","Next.js",{"slug":1224,"path":966,"title":5,"date":961,"tags":1225,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":171},"minicode-source-analysis",[970,971,972,973,974],{"slug":1227,"path":1228,"title":1229,"date":961,"tags":1230,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":134},"nova-theme-implementation","\u002Fposts\u002Fnova-theme-implementation","我是怎么从零实现 Nova 主题的",[1231,1232,1233],"Hexo","前端","开源",{"slug":1235,"path":1236,"title":1237,"date":1238,"tags":1239,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":77},"git-cheatsheet","\u002Fposts\u002Fgit-cheatsheet","Git 常用操作备忘","2026-04-05 14:00:00",[1240,405],"Git",{"slug":1242,"path":1243,"title":1244,"date":1245,"tags":1246,"description":35,"draft":963,"hidden":963,"published":161,"readingTime":113},"github-actions-intro","\u002Fposts\u002Fgithub-actions-intro","GitHub Actions 入门：自动化你的工作流","2026-04-04 09:00:00",[1247,1248,1249],"GitHub Actions","CI\u002FCD","自动化",1782796012481]