feat: support reasoning models like DeepSeek R1
This commit is contained in:
@ -29,6 +29,7 @@ export type PartialSearchResult = DeepPartial<SearchResult>
|
||||
|
||||
export type ResearchStep =
|
||||
| { type: 'generating_query'; result: PartialSearchQuery; nodeId: string }
|
||||
| { type: 'generating_query_reasoning'; delta: string; nodeId: string }
|
||||
| {
|
||||
type: 'generated_query'
|
||||
query: string
|
||||
@ -43,6 +44,11 @@ export type ResearchStep =
|
||||
result: PartialSearchResult
|
||||
nodeId: string
|
||||
}
|
||||
| {
|
||||
type: 'processing_serach_result_reasoning'
|
||||
delta: string
|
||||
nodeId: string
|
||||
}
|
||||
| {
|
||||
type: 'processed_search_result'
|
||||
query: string
|
||||
@ -110,7 +116,7 @@ export function generateSearchQueries({
|
||||
'\n',
|
||||
)}`
|
||||
: '',
|
||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||
`You MUST respond in JSON matching this JSON schema: ${jsonSchema}`,
|
||||
lp,
|
||||
].join('\n\n')
|
||||
return streamText({
|
||||
@ -160,7 +166,7 @@ function processSearchResult({
|
||||
`<contents>${contents
|
||||
.map((content) => `<content>\n${content}\n</content>`)
|
||||
.join('\n')}</contents>`,
|
||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||
`You MUST respond in JSON matching this JSON schema: ${jsonSchema}`,
|
||||
languagePrompt(language),
|
||||
].join('\n\n')
|
||||
|
||||
@ -234,6 +240,8 @@ export async function deepResearch({
|
||||
/** Force the LLM to generate serp queries in a certain language */
|
||||
searchLanguage?: string
|
||||
}): Promise<ResearchResult> {
|
||||
const { t } = useNuxtApp().$i18n
|
||||
|
||||
try {
|
||||
const searchQueriesResult = generateSearchQueries({
|
||||
query,
|
||||
@ -246,12 +254,12 @@ export async function deepResearch({
|
||||
|
||||
let searchQueries: PartialSearchQuery[] = []
|
||||
|
||||
for await (const parsedQueries of parseStreamingJson(
|
||||
searchQueriesResult.textStream,
|
||||
for await (const chunk of parseStreamingJson(
|
||||
searchQueriesResult.fullStream,
|
||||
searchQueriesTypeSchema,
|
||||
(value) => !!value.queries?.length && !!value.queries[0]?.query,
|
||||
)) {
|
||||
if (parsedQueries.queries) {
|
||||
if (chunk.type === 'object' && chunk.value.queries) {
|
||||
for (let i = 0; i < searchQueries.length; i++) {
|
||||
onProgress({
|
||||
type: 'generating_query',
|
||||
@ -259,7 +267,27 @@ export async function deepResearch({
|
||||
nodeId: childNodeId(nodeId, i),
|
||||
})
|
||||
}
|
||||
searchQueries = parsedQueries.queries
|
||||
searchQueries = chunk.value.queries
|
||||
} else if (chunk.type === 'reasoning') {
|
||||
onProgress({
|
||||
type: 'generating_query_reasoning',
|
||||
delta: chunk.delta,
|
||||
nodeId,
|
||||
})
|
||||
} else if (chunk.type === 'error') {
|
||||
onProgress({
|
||||
type: 'error',
|
||||
message: chunk.message,
|
||||
nodeId,
|
||||
})
|
||||
break
|
||||
} else if (chunk.type === 'bad-end') {
|
||||
onProgress({
|
||||
type: 'error',
|
||||
message: t('invalidStructuredOutput'),
|
||||
nodeId,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,6 +300,7 @@ export async function deepResearch({
|
||||
})
|
||||
}
|
||||
|
||||
// Run in parallel and limit the concurrency
|
||||
const results = await Promise.all(
|
||||
searchQueries.map((searchQuery, i) =>
|
||||
limit(async () => {
|
||||
@ -287,6 +316,7 @@ export async function deepResearch({
|
||||
nodeId: childNodeId(nodeId, i),
|
||||
})
|
||||
try {
|
||||
// Use Tavily to search the web
|
||||
const result = await useTavily().search(searchQuery.query, {
|
||||
maxResults: 5,
|
||||
})
|
||||
@ -314,18 +344,41 @@ export async function deepResearch({
|
||||
})
|
||||
let searchResult: PartialSearchResult = {}
|
||||
|
||||
for await (const parsedLearnings of parseStreamingJson(
|
||||
searchResultGenerator.textStream,
|
||||
for await (const chunk of parseStreamingJson(
|
||||
searchResultGenerator.fullStream,
|
||||
searchResultTypeSchema,
|
||||
(value) => !!value.learnings?.length,
|
||||
)) {
|
||||
searchResult = parsedLearnings
|
||||
onProgress({
|
||||
type: 'processing_serach_result',
|
||||
result: parsedLearnings,
|
||||
query: searchQuery.query,
|
||||
nodeId: childNodeId(nodeId, i),
|
||||
})
|
||||
const id = childNodeId(nodeId, i)
|
||||
if (chunk.type === 'object') {
|
||||
searchResult = chunk.value
|
||||
onProgress({
|
||||
type: 'processing_serach_result',
|
||||
result: chunk.value,
|
||||
query: searchQuery.query,
|
||||
nodeId: id,
|
||||
})
|
||||
} else if (chunk.type === 'reasoning') {
|
||||
onProgress({
|
||||
type: 'processing_serach_result_reasoning',
|
||||
delta: chunk.delta,
|
||||
nodeId: id,
|
||||
})
|
||||
} else if (chunk.type === 'error') {
|
||||
onProgress({
|
||||
type: 'error',
|
||||
message: chunk.message,
|
||||
nodeId: id,
|
||||
})
|
||||
break
|
||||
} else if (chunk.type === 'bad-end') {
|
||||
onProgress({
|
||||
type: 'error',
|
||||
message: t('invalidStructuredOutput'),
|
||||
nodeId: id,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
console.log(
|
||||
`Processed search result for ${searchQuery.query}`,
|
||||
|
@ -28,7 +28,7 @@ export function generateFeedback({
|
||||
const jsonSchema = JSON.stringify(zodToJsonSchema(schema))
|
||||
const prompt = [
|
||||
`Given the following query from the user, ask ${numQuestions} follow up questions to clarify the research direction. Return a maximum of ${numQuestions} questions, but feel free to return less if the original query is clear: <query>${query}</query>`,
|
||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||
`You MUST respond in JSON matching this JSON schema: ${jsonSchema}`,
|
||||
languagePrompt(language),
|
||||
].join('\n\n')
|
||||
|
||||
@ -37,12 +37,13 @@ export function generateFeedback({
|
||||
system: systemPrompt(),
|
||||
prompt,
|
||||
onError({ error }) {
|
||||
console.error(`generateFeedback`, error)
|
||||
throw error
|
||||
},
|
||||
})
|
||||
|
||||
return parseStreamingJson(
|
||||
stream.textStream,
|
||||
stream.fullStream,
|
||||
feedbackTypeSchema,
|
||||
(value: PartialFeedback) => !!value.questions && value.questions.length > 0,
|
||||
)
|
||||
|
Reference in New Issue
Block a user