Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
8271ef53
authored
Jun 29, 2026
by
Finley Ge
Committed by
GitHub
Jun 29, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: sanitize private tool schema fields (#7207)
parent
ff1a1a10
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
114 additions
and
3 deletions
+114
-3
packages/service/core/ai/llm/request/requestBody.ts
+39
-3
packages/service/test/core/ai/llm/request/requestBody.test.ts
+75
-0
No files found.
packages/service/core/ai/llm/request/requestBody.ts
View file @
8271ef53
import
type
{
ChatCompletionCreateParams
}
from
'@fastgpt/global/core/ai/llm/type'
;
import
type
{
ChatCompletionCreateParams
,
ChatCompletionTool
}
from
'@fastgpt/global/core/ai/llm/type'
;
import
{
getLLMSupportParams
}
from
'@fastgpt/global/core/ai/llm/utils'
;
import
json5
from
'json5'
;
import
{
computedMaxToken
,
computedTemperature
}
from
'../../utils'
;
...
...
@@ -6,6 +9,38 @@ import { getLLMModel } from '../../model';
import
type
{
InferCompletionsBody
,
LLMRequestBodyType
}
from
'./types'
;
import
type
{
LLMModelItemType
}
from
'@fastgpt/global/core/ai/model.schema'
;
const
privateToolSchemaKeys
=
new
Set
([
'toolDescription'
,
'x-tool-description'
,
'isSecret'
]);
/**
* 清理 FastGPT 内部工具参数扩展字段,避免 OpenAI-compatible SDK 转成 Gemini 等原生
* function declaration 时,把 toolDescription 这类非供应商 schema 字段透传出去。
*/
const
sanitizeToolParametersSchema
=
(
schema
:
unknown
):
unknown
=>
{
if
(
Array
.
isArray
(
schema
))
{
return
schema
.
map
(
sanitizeToolParametersSchema
);
}
if
(
!
schema
||
typeof
schema
!==
'object'
)
{
return
schema
;
}
return
Object
.
fromEntries
(
Object
.
entries
(
schema
as
Record
<
string
,
unknown
>
)
.
filter
(([
key
])
=>
!
privateToolSchemaKeys
.
has
(
key
))
.
map
(([
key
,
value
])
=>
[
key
,
sanitizeToolParametersSchema
(
value
)])
);
};
const
sanitizeCompletionTools
=
(
tools
?:
ChatCompletionTool
[]):
ChatCompletionTool
[]
|
undefined
=>
tools
?.
map
((
tool
)
=>
({
...
tool
,
function
:
{
...
tool
.
function
,
parameters
:
sanitizeToolParametersSchema
(
tool
.
function
.
parameters
)
as
ChatCompletionTool
[
'function'
][
'parameters'
]
}
}));
/**
* 把 FastGPT 内部 LLM body 转成 OpenAI SDK 可请求的 completions body。
*
...
...
@@ -22,6 +57,7 @@ export const llmCompletionsBodyFormat = async <T extends ChatCompletionCreatePar
modelData
:
LLMModelItemType
;
}
>
=>
{
const
{
tools
,
tool_choice
,
parallel_tool_calls
,
toolCallMode
,
...
body
}
=
input
;
const
sanitizedTools
=
sanitizeCompletionTools
(
tools
);
// 这些字段只影响 FastGPT 自身逻辑,不能透传给模型供应商。
delete
body
.
retainDatasetCite
;
delete
body
.
useVision
;
...
...
@@ -82,8 +118,8 @@ export const llmCompletionsBodyFormat = async <T extends ChatCompletionCreatePar
stop
:
formatStop
?.
length
?
formatStop
:
undefined
,
// prompt tool 模式通过 prompt 描述工具,直接传 tools 会让部分模型同时触发两套协议。
...(
toolCallMode
===
'toolChoice'
&&
t
ools
?.
length
&&
{
tools
,
sanitizedT
ools
?.
length
&&
{
tools
:
sanitizedTools
,
tool_choice
,
parallel_tool_calls
})
...
...
packages/service/test/core/ai/llm/request/requestBody.test.ts
View file @
8271ef53
...
...
@@ -151,6 +151,81 @@ describe('llmCompletionsBodyFormat', () => {
expect
(
requestBody
).
not
.
toHaveProperty
(
'tools'
);
});
it
(
'should remove FastGPT private tool schema fields before sending tools to model'
,
async
()
=>
{
mockGetLLMModel
.
mockReturnValue
(
createModel
());
const
{
requestBody
}
=
await
llmCompletionsBodyFormat
({
model
:
'gpt-4o'
,
messages
,
stream
:
false
,
tools
:
[
{
type
:
'function'
,
function
:
{
name
:
'search'
,
description
:
'search'
,
parameters
:
{
type
:
'object'
,
properties
:
{
query
:
{
type
:
'string'
,
description
:
'Search query'
,
toolDescription
:
'Query for model'
,
'x-tool-description'
:
'HTTP query'
,
isSecret
:
true
},
filters
:
{
type
:
'array'
,
items
:
{
type
:
'object'
,
properties
:
{
key
:
{
type
:
'string'
,
toolDescription
:
'Filter key'
}
},
toolDescription
:
'Filter object'
}
}
}
}
}
}
],
toolCallMode
:
'toolChoice'
});
expect
(
requestBody
.
tools
).
toEqual
([
{
type
:
'function'
,
function
:
{
name
:
'search'
,
description
:
'search'
,
parameters
:
{
type
:
'object'
,
properties
:
{
query
:
{
type
:
'string'
,
description
:
'Search query'
},
filters
:
{
type
:
'array'
,
items
:
{
type
:
'object'
,
properties
:
{
key
:
{
type
:
'string'
}
}
}
}
}
}
}
}
]);
});
it
(
'should apply field map after base formatting'
,
async
()
=>
{
mockGetLLMModel
.
mockReturnValue
(
createModel
({
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment