mirror of
https://github.com/jina-ai/node-DeepResearch.git
synced 2025-12-26 06:28:56 +08:00
refactor: schemas
This commit is contained in:
parent
66490f3848
commit
cf403302a9
@ -181,7 +181,6 @@ ${allKeywords.join('\n')}
|
||||
actionSections.push(`
|
||||
<action-answer>
|
||||
- For greetings, casual conversation, or general knowledge questions, answer directly without references.
|
||||
- If the question is clearly within your knowledge cutoff (i.e. Aug. 2024) and requires no up-to-date knowledge to get better answer, then provide a confident answer directly.
|
||||
- For all other questions, provide a verified answer with references. Each reference must include exactQuote and url.
|
||||
- If uncertain, use <action-reflect>
|
||||
</action-answer>
|
||||
@ -356,11 +355,11 @@ export async function getResponse(question?: string,
|
||||
return {
|
||||
exactQuote: ref.exactQuote,
|
||||
title: allURLs[ref.url]?.title,
|
||||
url: normalizeUrl(ref.url)
|
||||
url: ref.url ? normalizeUrl(ref.url) : ''
|
||||
}
|
||||
});
|
||||
|
||||
context.actionTracker.trackThink(`But wait, let me evaluate the answer first.`)
|
||||
context.actionTracker.trackThink('eval_first', SchemaGen.languageCode)
|
||||
|
||||
const evaluation = await evaluateAnswer(currentQuestion, thisStep,
|
||||
evaluationMetrics[currentQuestion],
|
||||
@ -506,7 +505,7 @@ But then you realized you have asked them before. You decided to to think out of
|
||||
if (keywordsQueries.length > 0) {
|
||||
|
||||
|
||||
context.actionTracker.trackThink(`Let me search for "${keywordsQueries.join(', ')}" to gather more information.`)
|
||||
context.actionTracker.trackThink('search_for', SchemaGen.languageCode, {keywords: keywordsQueries.join(', ')});
|
||||
for (const query of keywordsQueries) {
|
||||
console.log(`Search query: ${query}`);
|
||||
|
||||
@ -594,7 +593,7 @@ You decided to think out of the box or cut from a completely different angle.
|
||||
const uniqueURLs = thisStep.URLTargets;
|
||||
|
||||
if (uniqueURLs.length > 0) {
|
||||
context.actionTracker.trackThink(`Let me read ${uniqueURLs.join(', ')} to gather more information.`);
|
||||
context.actionTracker.trackThink('read_for', SchemaGen.languageCode, {urls: uniqueURLs.join(', ')});
|
||||
|
||||
const urlResults = await Promise.all(
|
||||
uniqueURLs.map(async url => {
|
||||
|
||||
@ -132,7 +132,7 @@ function calculateDelay(chunk: string, burstMode: boolean): number {
|
||||
|
||||
// Special handling for CJK characters
|
||||
if (/^[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]$/.test(chunk)) {
|
||||
return Math.random() * 50 + 10; // Longer delay for individual CJK characters
|
||||
return Math.random() * 25 + 10; // Longer delay for individual CJK characters
|
||||
}
|
||||
|
||||
// Base delay calculation
|
||||
|
||||
@ -474,7 +474,9 @@ Question: "请解释赤壁之战的历史背景、主要参与者以及战略意
|
||||
</examples>
|
||||
|
||||
Now evaluate this question:
|
||||
Question: ${question}`;
|
||||
Question: ${question}
|
||||
|
||||
NOTE: "think" field should be in the same language as the question`;
|
||||
}
|
||||
|
||||
const TOOL_NAME = 'evaluator';
|
||||
@ -560,7 +562,7 @@ export async function evaluateAnswer(
|
||||
case 'attribution': {
|
||||
// Safely handle references and ensure we have content
|
||||
|
||||
const allKnowledge = await fetchSourceContent(uniqueNewURLs, trackers);
|
||||
const allKnowledge = await fetchSourceContent(uniqueNewURLs, trackers, schemaGen);
|
||||
visitedURLs.push(...uniqueNewURLs);
|
||||
|
||||
if (allKnowledge.trim().length === 0) {
|
||||
@ -610,9 +612,9 @@ export async function evaluateAnswer(
|
||||
}
|
||||
|
||||
// Helper function to fetch and combine source content
|
||||
async function fetchSourceContent(urls: string[], trackers: TrackerContext): Promise<string> {
|
||||
async function fetchSourceContent(urls: string[], trackers: TrackerContext, schemaGen: Schemas): Promise<string> {
|
||||
if (!urls.length) return '';
|
||||
trackers.actionTracker.trackThink('Let me fetch the source content to verify the answer.');
|
||||
trackers.actionTracker.trackThink('read_for_verify', schemaGen.languageCode);
|
||||
try {
|
||||
const results = await Promise.all(
|
||||
urls.map(async (url) => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { StepAction } from '../types';
|
||||
import {EventEmitter} from 'events';
|
||||
import {StepAction} from '../types';
|
||||
import {getI18nText} from "./text-tools";
|
||||
|
||||
interface ActionState {
|
||||
thisStep: StepAction;
|
||||
@ -8,6 +9,7 @@ interface ActionState {
|
||||
totalStep: number;
|
||||
}
|
||||
|
||||
|
||||
export class ActionTracker extends EventEmitter {
|
||||
private state: ActionState = {
|
||||
thisStep: {action: 'answer', answer: '', references: [], think: ''},
|
||||
@ -17,18 +19,20 @@ export class ActionTracker extends EventEmitter {
|
||||
};
|
||||
|
||||
trackAction(newState: Partial<ActionState>) {
|
||||
this.state = { ...this.state, ...newState };
|
||||
this.state = {...this.state, ...newState};
|
||||
this.emit('action', this.state.thisStep);
|
||||
}
|
||||
|
||||
trackThink(think: string) {
|
||||
// only update the think field of the current state
|
||||
this.state = { ...this.state, thisStep: { ...this.state.thisStep, think } };
|
||||
trackThink(think: string, lang?: string, params = {}) {
|
||||
if (lang) {
|
||||
think = getI18nText(think, lang, params);
|
||||
}
|
||||
this.state = {...this.state, thisStep: {...this.state.thisStep, think}};
|
||||
this.emit('action', this.state.thisStep);
|
||||
}
|
||||
|
||||
getState(): ActionState {
|
||||
return { ...this.state };
|
||||
return {...this.state};
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
||||
86
src/utils/i18n.json
Normal file
86
src/utils/i18n.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"en": {
|
||||
"eval_first": "But wait, let me evaluate the answer first.",
|
||||
"search_for": "Let me search for ${keywords} to gather more information.",
|
||||
"read_for": "Let me read ${urls} to gather more information.",
|
||||
"read_for_verify": "Let me fetch the source content to verify the answer."
|
||||
},
|
||||
"zh-CN": {
|
||||
"eval_first": "等等,让我先自己评估一下答案。",
|
||||
"search_for": "让我搜索${keywords}来获取更多信息。",
|
||||
"read_for": "让我读取网页${urls}来获取更多信息。",
|
||||
"read_for_verify": "让我读取源网页内容来验证答案。"
|
||||
},
|
||||
"zh-TW": {
|
||||
"eval_first": "等等,讓我先評估一下答案。",
|
||||
"search_for": "讓我搜索${keywords}來獲取更多信息。",
|
||||
"read_for": "讓我閱讀${urls}來獲取更多信息。",
|
||||
"read_for_verify": "讓我獲取源內容來驗證答案。"
|
||||
},
|
||||
"ja": {
|
||||
"eval_first": "ちょっと待って、まず答えを評価します。",
|
||||
"search_for": "キーワード${keywords}で検索して、情報を集めます。",
|
||||
"read_for": "URL${urls}を読んで、情報を集めます。",
|
||||
"read_for_verify": "答えを確認するために、ソースコンテンツを取得します。"
|
||||
},
|
||||
"ko": {
|
||||
"eval_first": "잠시만요, 먼저 답변을 평가해 보겠습니다.",
|
||||
"search_for": "키워드 ${keywords}로 검색하여 더 많은 정보를 수집하겠습니다.",
|
||||
"read_for": "URL ${urls}을 읽어 더 많은 정보를 수집하겠습니다.",
|
||||
"read_for_verify": "답변을 확인하기 위해 소스 콘텐츠를 가져오겠습니다."
|
||||
},
|
||||
"fr": {
|
||||
"eval_first": "Un instant, je vais d'abord évaluer la réponse.",
|
||||
"search_for": "Je vais rechercher ${keywords} pour obtenir plus d'informations.",
|
||||
"read_for": "Je vais lire ${urls} pour obtenir plus d'informations.",
|
||||
"read_for_verify": "Je vais récupérer le contenu source pour vérifier la réponse."
|
||||
},
|
||||
"de": {
|
||||
"eval_first": "Einen Moment, ich werde die Antwort zuerst evaluieren.",
|
||||
"search_for": "Ich werde nach ${keywords} suchen, um weitere Informationen zu sammeln.",
|
||||
"read_for": "Ich werde ${urls} lesen, um weitere Informationen zu sammeln.",
|
||||
"read_for_verify": "Ich werde den Quellinhalt abrufen, um die Antwort zu überprüfen."
|
||||
},
|
||||
"es": {
|
||||
"eval_first": "Un momento, voy a evaluar la respuesta primero.",
|
||||
"search_for": "Voy a buscar ${keywords} para recopilar más información.",
|
||||
"read_for": "Voy a leer ${urls} para recopilar más información.",
|
||||
"read_for_verify": "Voy a obtener el contenido fuente para verificar la respuesta."
|
||||
},
|
||||
"it": {
|
||||
"eval_first": "Un attimo, valuterò prima la risposta.",
|
||||
"search_for": "Cercherò ${keywords} per raccogliere ulteriori informazioni.",
|
||||
"read_for": "Leggerò ${urls} per raccogliere ulteriori informazioni.",
|
||||
"read_for_verify": "Recupererò il contenuto sorgente per verificare la risposta."
|
||||
},
|
||||
"pt": {
|
||||
"eval_first": "Um momento, vou avaliar a resposta primeiro.",
|
||||
"search_for": "Vou pesquisar ${keywords} para reunir mais informações.",
|
||||
"read_for": "Vou ler ${urls} para reunir mais informações.",
|
||||
"read_for_verify": "Vou buscar o conteúdo da fonte para verificar a resposta."
|
||||
},
|
||||
"ru": {
|
||||
"eval_first": "Подождите, я сначала оценю ответ.",
|
||||
"search_for": "Дайте мне поискать ${keywords} для сбора дополнительной информации.",
|
||||
"read_for": "Дайте мне прочитать ${urls} для сбора дополнительной информации.",
|
||||
"read_for_verify": "Дайте мне получить исходный контент для проверки ответа."
|
||||
},
|
||||
"ar": {
|
||||
"eval_first": "لكن انتظر، دعني أقوم بتقييم الإجابة أولاً.",
|
||||
"search_for": "دعني أبحث عن ${keywords} لجمع المزيد من المعلومات.",
|
||||
"read_for": "دعني أقرأ ${urls} لجمع المزيد من المعلومات.",
|
||||
"read_for_verify": "دعني أحضر محتوى المصدر للتحقق من الإجابة."
|
||||
},
|
||||
"nl": {
|
||||
"eval_first": "Een moment, ik zal het antwoord eerst evalueren.",
|
||||
"search_for": "Ik zal zoeken naar ${keywords} om meer informatie te verzamelen.",
|
||||
"read_for": "Ik zal ${urls} lezen om meer informatie te verzamelen.",
|
||||
"read_for_verify": "Ik zal de broninhoud ophalen om het antwoord te verifiëren."
|
||||
},
|
||||
"zh": {
|
||||
"eval_first": "等等,让我先评估一下答案。",
|
||||
"search_for": "让我搜索${keywords}来获取更多信息。",
|
||||
"read_for": "让我阅读${urls}来获取更多信息。",
|
||||
"read_for_verify": "让我获取源内容来验证答案。"
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@ ${question}`;
|
||||
|
||||
export class Schemas {
|
||||
private languageStyle: string = 'formal English';
|
||||
private languageCode: string = 'en';
|
||||
public languageCode: string = 'en';
|
||||
|
||||
|
||||
constructor(query: string) {
|
||||
|
||||
@ -125,3 +125,39 @@ export function chooseK(a: string[], k: number) {
|
||||
export function removeHTMLtags(text: string) {
|
||||
return text.replace(/<[^>]*>?/gm, '');
|
||||
}
|
||||
|
||||
|
||||
export function getI18nText(key: string, lang = 'en', params: Record<string, string> = {}) {
|
||||
// 获取i18n数据
|
||||
const i18nData = require('./i18n.json');
|
||||
|
||||
// 确保语言代码存在,如果不存在则使用英语作为后备
|
||||
if (!i18nData[lang]) {
|
||||
console.error(`Language '${lang}' not found, falling back to English.`);
|
||||
lang = 'en';
|
||||
}
|
||||
|
||||
// 获取对应语言的文本
|
||||
let text = i18nData[lang][key];
|
||||
|
||||
// 如果文本不存在,则使用英语作为后备
|
||||
if (!text) {
|
||||
console.error(`Key '${key}' not found for language '${lang}', falling back to English.`);
|
||||
text = i18nData['en'][key];
|
||||
|
||||
// 如果英语版本也不存在,则返回键名
|
||||
if (!text) {
|
||||
console.error(`Key '${key}' not found for English either.`);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
// 替换模板中的变量
|
||||
if (params) {
|
||||
Object.keys(params).forEach(paramKey => {
|
||||
text = text.replace(`\${${paramKey}}`, params[paramKey]);
|
||||
});
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user