96SEO 2026-08-02 04:20 2
👤 关于作者
JavaAgent架构师 — 十年 Java 分布式架构老兵,专注 AI Agent 公司级落地。

主导过数字员工、SOP 智能引擎等项目,开发过 RPC 框架、消息中间件、ORM 框架。按理说,
专栏:
让 Java 开发者不转 Python 也能建立公司级 AI 应用。
点赞+关注+评论 走一波。
使用者痛点:
arguments 为 JSON 字符串,很多团队在前端直接当对象使用导致解析错误。传统的交互模型是:使用者操作 → 前端发请求 → 后端处理 → 前端展示结果。Function Calling 将模型改为:
↓ 请求带 tools 定义
← LLM 返回 function_call
↓ 前端解析 + 执行函数
← 将执行结果回传给 LLM
→ 最终文本回复
interface ChatCompletionRequest {
model的观点是,string;messages: ChatMessage;tools,: ToolDefinition;tool_choice,: 'auto' | 'none' | { type: 'function';function: { name: string } };}
interface ToolDefinition {
从type来看,'function';老实说,function: {
至于name,string;description: string;// LLM 靠描述决定何时调用
parameters: {
type这方面,'object';properties: Record;required,: string;},};}
interface PropertyDefinition {
type的观点是,string;description: string;enum,: string;// 枚举约束
}
// 示例:天气查询工具
const wearTool: ToolDefinition = {
再看type,'function',function: {
至于name,'get_wear',description: '获取指定城市的当前天气信息',parameters: {
再看type。'object',properties: {
说到city,{ type: 'string',description: '城市名称,如"北京","上海"' },unit: { type: 'string',description: '温度单位',enum: },},required:,},},};
// 当 LLM 决定调用工具时的响应结构
interface FunctionCallResponse {
至于id,string;// chatcmpl-xxx
choices:;},finish_reason:'tool_calls';// 因工具调用而停止
}];}
关键细节:arguments 必须先使用 JSON.parse 转为对象。否则会出现类型错误,这是最常见的 bug 源头。
┌───────────────────────────────────────┐
│ FunctionCallingExecutor │
├───────────────────────────────────────┤
│ 工具注册层 │
│ ├─ registerTool│
│ └─ 工具元数据 │
├───────────────────────────────────────┤
│ 参数校验层 │
│ ├─ Schema 校验 │
│ └─ 安全过滤 │
├───────────────────────────────────────┤
│ 执行层 │
│ ├─ 权限检查 │
│ ├─ 沙箱执行 │
│ ├─ 超时控制 │
│ └─ 并发并行执行 │
├───────────────────────────────────────┤
│ 결과处理层 │
│ ├─ 序列化 │
│ ├─ 错误捕获与格式化 │
│ └─ 构造回传消息 │
└───────────────────────────────────────┘
type ToolPermission = 'read' | 'write' | 'dangerous';怎么说呢,interface ToolRegistration {
说到name。string,description:string;parameters:any;// JSON Schema
handler:=>Promise;permission:ToolPermission;老实说,_timeout?:number,_maxRetries?:number,}
class FunctionCallingExecutor {
private tools = new Map;private permissionLevel : ToolPermission = 'read';怎么说呢,// 当前允许最高权限
/** 注册单个工具 */
registerTool:void{
if{
throw new Error;}
this.tools.set;}
/** 批量注册 */
registerTools:void{
regs.forEach);}
/** 注销 */
unregisterTool:void{
this.tools.delete;}
/** 获取当前可见的 tool 定义,用于发送给 LLM */
getToolDefinitions:ToolDefinition{
return Array.from)
.filter)
.map(t=>({
从type来看。'function',// @ts-ignore
function:{name:t.name,description:t.description,parameters:t.parameters}
}));}
// 权限判断逻辑
private isPermissionAllowed:boolean{const levels:{:number}={read:1。width:2,risk:3};return levels<=levels;};话说回来,setPermissionLevel:void{this.permissionLevel=level;}
参数校验 & 安全过滤
import {z} from 'zod';class FunctionCallingExecutor {/* ... 前面的代码 ... */
async execute:Promise{
const {name,arguments:argsStr}=toolCall.function;const tool=this.tools.get;if{
return{tool_call_id:toolCall.id。role:'tool',content:JSON.stringify};}
if){
return{tool_call_id:toolCall.id。role:'tool',content:
JSON.stringify};}
let args:any;说起来,try{args=JSON.parse;}catch{
return{tool_call_id:。role:'tool',content:
JSON.stringify};按理说,}
if{
const result=tool.parameterSchema.safeParse;不过,if{
return{tool_call_id:。role:'tool',content:
JSON.stringify};其实,}
args=result.data;}
args=this.sanitizeArgs;try{
const res=await this.executeWithTimeout,tool.timeout?,3000);return{tool_call_id:,role:'tool'。content:
JSON.stringify)};怎么说呢,}catch{
return{tool_call_id:。role:'tool',content:
JSON.stringify};说起来,}
}
private sanitizeArgs:any{
if return this.sanitizeString;if{
const out=Array.isArray?:{},for){
out=this.sanitizeArgs;}
return out;其实,}
return v;}
private sanitizeString:string{
return s.replace
.replace
.replace;}
private sanitizeResult:any{/* 敏感信息过滤 */}
三、并行工具调用的并发执行
async executeAll(
toolCalls:Array<{id:string,type:'function',function:{name:string,arguments:string}}>
):Promise{
const results=await Promise.allSettled(
toolCalls.map)
);return results.map=>">
r.status==='fulfilled'?r.value:{
tool_call_id : toolCalls.id。role:'tool',content : JSON.stringify
};}),}
四、完整多轮 Function Calling 流程
class AIFunctionCallingOrchestrator{
private executor : FunctionCallingExecutor;private sseClient : SSEClient;private maxRounds =5;constructor{ this.executor=exec,this.sseClient=sse;其实,}
async chat : Promise{
let hist=;for{
const resp=await this.sendRequest;if{
return resp.content?,'';}
hist.push,const toolsRes=await this.executor.executeAll;toolsRes.forEach(r=>
hist.push);if throw new Error;}
}
private async sendRequest : Promise{
const r=await fetch('/api/chat'。{method:'POST',headers:{'Content-Type':'application/json'},body : JSON.stringify({
& nbsp;model:'gpt-4o-mini',& nbsp;messages,& nbsp;tools:this.executor.getToolDefinitions,& nbsp;tool_choice:'auto'
})});const d=await r.json;return d.choices.message;}
}
五、前端可注册的典型工具示例
// 天气查询
executor.registerTool({
name的观点是,'get_wear',description:'获取指定城市的当前天气',parameters:{
type这方面。'object',properties:{
至于city,{type:'string',description:'城市名称'},unit:{type:'string',description:'温度单位',enum:}
},required:
},parameterSchema:z.object.min}),handler : async =>{
const res=await fetch}`);return res.json;},permission:'read'
});// 网页搜索
executor.registerTool({
再看name,'web_search',description:'在互联网上搜索信息',parameters:{
再看type,'object',properties:{
query这方面,{type:'string',description:'搜索关键词'},count:{type:'number'。description:'返回数量'}
},required:
},parameterSchema:z.object,count:z.number.min.max.optional}),handler : async =>{
const r=await fetch('/api/search',{method:'POST',body:
JSON.stringify});return r.json;},permission :'read'
});// 危险代码执行
executor.registerTool({
name :'execute_code',description :'在沙箱中执行 JavaScript代码',parameters:{
type :'object',properties:{ code:{type :'string'。description :'JS代码'}},required:
},parameterSchema:z.object.max}),handler : async =>executeInSandbox,permission :'dangerous',timeout :5000,});老实说,
RAG 前端调整实战
RAG 不只是后端的事
-
LLM 检索到的不相关文档直接返回。使用者无法看到依据,导致信任度低。
-
高频相同查询每次都走向量检索和网络请求,延迟和成本居高不下。
-
检索结果只做文字堆砌,没有可视化方便使用者定位关键信息。其实,
-
User Feedback 缺失——后端无法感知哪些 chunk 真正有价值。难以迭代排序模型,不过,
-
LLM 在模糊查询上表现差。需要在前端对查询进行
召回率。话说回来,
一、RAG 链路中的前端调整点
使用者输入查询 → → 向量检索 → → 排序
↓ ↓
使用者反馈 ← ← 最终回答 ←
-
:基于对话上下文
或消歧。提高检索命中率,
-
:利用 IndexedDB 本地缓存高频向量检索及其返回;按理说,
-
:展示每个 chunk 的来源、相似度还有摘要;其实,
-
:记录点击/展开/忽略等交互。为后续 Rerank 提供监督信号。
二、查询
:前端侧的使用者意图
Pain Point:LLM 对简短或含指代的问题检索效果差,需要在前置阶段补全上下文。说起来,
class QueryRewriter{
private ctx:Array;constructor { this.ctx=context;}
/** 主入口 */
rewrite:string{
let r=q;r=this.resolveReferences;r=this.expandWithContext;r=this.enhanceKeywords;不过,return r,}
private resolveReferences:string{
const recent=this.ctx.slice;
话说回来,const entityPatterns=;let lastEntity='';老实说,for{
for{
const mch=m.content.match;if lastEntity=mch;老实说,}
}
if{
q=q.replace;}
return q,}
private expandWithContext:string{
if{
const lastUser=this.ctx.filter.pop?.content,if q=${q} }…),}
return q;}
private enhanceKeywords:string{
const synonyms={
再看'前端'。'组件':,'状态管理':,'渲染':
};let out=q,for){
if) out+=});}
return out;}
}
进阶方案: 使用轻量本地 LLM在浏览器完成一次语义
可进一步提高召回质量且费用远低于主模型。
三、向量检索缓存:IndexedDB 存储高频查询结果
Pain Point:LLM 每次都要重新计算 embedding 并请求后端向量库,导致响应时间>1s 且成本累积。
interface CachedRetrievalResult{
query这方面,string;documents:Array<>;timestamp:number;hitCount:number;}
interface RetrievedDocument{
id这方面,string;怎么说呢,content:string;score:number;metadata:{
至于source,string;chunkIndex:number;},}
class RAGFrontendCache{
private dbName='rag-cache';private storeName='retrievals';private db,:IDBDatabase;说起来,
async init{ this.db= await this.openDB;}
async get:Promise<>">
{
const tx=this.db.transaction;const store=tx.objectStore;const rec=await store.get;if return null;
// 超时失效
if-rec.timestamp>){
await this.delete;return null,}
// 更新命中次数
rec.hitCount++;const wtx=this.db.transaction;wtx.objectStore.put;return rec as CachedRetrievalResult;}
async set>) {
const tx=this.db.transaction;tx.objectStore.put({
…result,timestamp:Number)。hitCount:Number
});}
async delete{…}
async cleanup{…}
private openDB:Promise<$IDBDatabase>"…省略实现,";}
使用示例
typescript
class RAGFrontendOptimizer{
private cache=new RAGFrontendCache;constructor{ this.cache.init;}
async retrieve{
const rewritten=new QueryRewriter.rewrite;let cached = await this.cache.get;怎么说呢,if{
console.log;return cached.documents;}
// 未命中 -> 调用后端 API
const docs = await fetch('/api/rag/retrieve'。{method:"POST",body:JSON.stringify}).n);await this.cache.set),hitCount:-});return docs,}
}
四、文档切片可视化
Pain Point:LLM 给出的答案往往缺乏来源说明,使得业务方难以审计或追溯。
interface ChunkHighlight{
documentId:string;怎么说呢,chunkIndex:number;content:string;score:number;isHighlighted:boolean;}
class RAGVisualizationPanel{
private container!:HTMLElement;
constructor{ this.container = containerElmt;}
render>) {
this.container.innerHTML='';const header=document.createElement;header.className='rag-header';header.textContent=参考文档;this.container.appendChild;
chunks.forEach)));}
private createChunkItem>) {
const el=document.createElement;el.className=rag-chunk ${c.isHighlighted?'highlighted':''};el.dataset.chunkId=c.chunkIndex.toString;el.dataset.documentId=c.documentId;不过,
el.innerHTML=
<div class="rag-chunk-header">
< span class="rag-source">${c.documentId}</span>
< span class="rag-score">${.toFixed}%</span>
</div>
< div class="rag-chunk-content">${this.truncate}</div>;
el.addEventListener=>this.expandChunk);return el,}
private truncate{return txt.length<=len?txt:text.slice+'...';}
private expandChunk>) {
alert;// 实际项目可以弹出 modal 并同步高亮答案对应段落
}
}
五、使用者反馈驱动的 Rerank 信号采集
Pain Point:LM 模型无法直接感知哪些检索块被使用者认为有价值,导致持续出现“无关答案”。
interface RAGFeedback{
至于query,String,chunkId:String,documentId:String,feedbackType:"relevant"|"irrelevant"|"partially_relevant"。userAction:"clicked"|"ignored"|"expanded"|"copied",timestamp:Number,}
class RAGFeedbackCollector{
private feedbacks:RAGFeedback=;setCurrentQuery{this.currentQuery=q;怎么说呢,}
record{
this.feedbacks.push;// 实时上报至后端用于模型再训练 / 排序微调
fetch('/api/rag/feedback',{method:"POST"。headers:{'Content-Type':'application/json'},body:
JSON.stringify}).catch=>console.warn);}
observe{
containerElmt.addEventListener=>{
const target=.closest;ifreturn,const cid=target.dataset.chunkId!,const did=target.dataset.documentId!,this.record({
说到query,this.currentQuery,chunkId:id,documentId:didd。feedbackType:"relevant",userAction:"clicked",timestamp:Number)
});}),}
private currentQuery='';}
六、RAG 前端调整完整模块
class RAGFrontendEnhancer{
private rewriter=new QueryRewriter;private cache=new RAGFrontendCache;private visualizer!:RAGVisualizationPanel;private feedbackCollector=new RAGFeedbackCollector;其实,
constructor{
this.visualizer=new RAGVisualizationPanel;this.cache.init;this.feedbackCollector.observe;}
async query:Promise<{answer:String,sources:Array<>}>{
// 步骤1:查询
const rewritten=this.rewriter.rewrite;this.feedbackCollector.setCurrentQuery;不过,
// 步骤2:缓存读取
let cached = await this.cache.get;let docs:Array<>;
if{
console.log;docs=cached.documents;}else{
// 步骤3:后端向量检索
docs = await fetch('/api/rag/retrieve',{
至于method。"POST",headers:{'Content-Type':'application/json'},body)
}).n);
await this.cache.set({
说到query。s,documents:DOCS,timestamp:Number),hitCount:-1});}
// 步骤4:可视化展示
this.visualizer.render(docs.map(d=>({
documentId:d.metadata.source。chunkIndex:d.metadata.chunkIndex,content:d.content,score:d.score,isHighlighted:false}))
);
// 步骤5:基于检索块生成答案
const answer = await fetch('/api/rag/generate'。{
说到method,"POST",headers:{'Content-Type':'application/json'},body)
}).n);
return {answer:s.answer,sources:this.visualizer||};}
}
实践任务 – FunctionCallingExecutor 实现要求
-
实现一个支持动态注册 / 注销工具的 Executor;
-
使用 Zod 完成参数 Schema 校验;
-
实现 read / write / dangerous 三层权限控制;
-
支持多工具并行调用;
-
加入超时控制与错误兜底;
-
实现敏感信息过滤逻辑。
<\/ul>
实践任务 – RAG 前端提高模块实现要求
-
查询
器需实现指代消解、上下文
和关键词提高;
-
使用 IndexedDB 缓存高频查询,每条记录默认保留1 小时;
-
提供 Chunk 可视化面板。展示来源、相似度及内容预览,并支持点击展开;
-
收集使用者对每个 Chunk 的点击 / 展开等行为并实时上报后端 API;怎么说呢,
<\/ul>
面试题解析 – FunctionCalling 流程要点
Q :前端如何处理 LLM 的 Function Calling 流程?
-
协议理解:> arguments 为 JSON 字符串,需要安全 parse。<\/ li>
-
执行步骤:> 查找工具 → 权限检查 → 参数校验 → XSS 防护 → 沙箱或普通执行 → 超时控制 → 格式化返回。\<\/ li>
-
并发处理:> 多 tool_calls 使用 Promise.allSettled 容忍局部失败。\<\/ li>
-
多轮循环:> 工具结果回传后继续让 LLM 基于新上下文决定是否
调用。\<\/ li>
-
安全防线:> 参数 Schema + XSS 清理 + 敏感字段过滤 + 最大轮数限制。\<\/ ul>
Q :RAG 在前侧可以做哪些调整?
-
基于对话上下文进行指代消解与关键词同义词
让向量召回更精准。<\/ li>
-
利用 IndexedDB 缓存 embedding 与检索结果,大幅降低网络 RTT 与算力成本。<\/ li>
-
将每个命中文档块以卡片形式呈现。并标注相似度与来源,提高透明度与信任感。<\/ l i>
-
捕获点击 / 展开 / 忽略等行为,将结构化反馈上报用于离线 rerank 或在线排序微调。<\/ l i>
/主要洞察/<\/ p>
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback