mirror of
https://github.com/jina-ai/node-DeepResearch.git
synced 2026-03-22 07:29:35 +08:00
chore: first commit
This commit is contained in:
40
src/agent.ts
40
src/agent.ts
@@ -7,7 +7,7 @@ import {SafeSearchType, search} from "duck-duck-scrape";
|
|||||||
import {rewriteQuery} from "./tools/query-rewriter";
|
import {rewriteQuery} from "./tools/query-rewriter";
|
||||||
import {dedupQueries} from "./tools/dedup";
|
import {dedupQueries} from "./tools/dedup";
|
||||||
import {evaluateAnswer} from "./tools/evaluator";
|
import {evaluateAnswer} from "./tools/evaluator";
|
||||||
import {buildURLMap} from "./tools/getURLIndex";
|
import {buildURLMap, StepData} from "./tools/getURLIndex";
|
||||||
|
|
||||||
// Proxy setup remains the same
|
// Proxy setup remains the same
|
||||||
if (process.env.https_proxy) {
|
if (process.env.https_proxy) {
|
||||||
@@ -111,7 +111,7 @@ function getSchema(allowReflect: boolean, allowRead: boolean): ResponseSchema {
|
|||||||
actions.push("reflect");
|
actions.push("reflect");
|
||||||
}
|
}
|
||||||
if (allowRead) {
|
if (allowRead) {
|
||||||
actions.push("read");
|
actions.push("visit");
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: SchemaType.OBJECT,
|
type: SchemaType.OBJECT,
|
||||||
@@ -213,13 +213,13 @@ ${JSON.stringify(context, null, 2)}
|
|||||||
When uncertain or needing additional information, select one of these actions:
|
When uncertain or needing additional information, select one of these actions:
|
||||||
|
|
||||||
${allURLs ? `
|
${allURLs ? `
|
||||||
**read**:
|
**visit**:
|
||||||
- Access any URLs from below to gather external knowledge
|
- Visit any URLs from below to gather external knowledge
|
||||||
|
|
||||||
${JSON.stringify(allURLs, null, 2)}
|
${JSON.stringify(allURLs, null, 2)}
|
||||||
|
|
||||||
- When you have enough search result in the context and want to deep dive into specific URLs
|
- When you have enough search result in the context and want to deep dive into specific URLs
|
||||||
- It allows you access the full content behind any URLs
|
- It allows you to access the full content behind any URLs
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
**search**:
|
**search**:
|
||||||
@@ -269,9 +269,16 @@ Critical Requirements:
|
|||||||
- Maintain strict JSON syntax`.trim();
|
- Maintain strict JSON syntax`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getResponse(question: string, tokenBudget: number = 30000000) {
|
let context: StepData[] = []; // successful steps in the current session
|
||||||
|
let allContext: StepData[] = []; // all steps in the current session, including those leads to wrong results
|
||||||
|
|
||||||
|
function updateContext(step: any) {
|
||||||
|
context.push(step);
|
||||||
|
allContext.push(step)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResponse(question: string, tokenBudget: number = 1000000) {
|
||||||
let totalTokens = 0;
|
let totalTokens = 0;
|
||||||
let context = [];
|
|
||||||
let step = 0;
|
let step = 0;
|
||||||
let gaps: string[] = [question]; // All questions to be answered including the orginal question
|
let gaps: string[] = [question]; // All questions to be answered including the orginal question
|
||||||
let allQuestions = [question];
|
let allQuestions = [question];
|
||||||
@@ -288,7 +295,7 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
const allowReflect = gaps.length <= 1;
|
const allowReflect = gaps.length <= 1;
|
||||||
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
||||||
// update all urls with buildURLMap
|
// update all urls with buildURLMap
|
||||||
allURLs = {...allURLs, ...buildURLMap(context)};
|
allURLs = buildURLMap(allContext);
|
||||||
const allowRead = Object.keys(allURLs).length > 0;
|
const allowRead = Object.keys(allURLs).length > 0;
|
||||||
const prompt = getPrompt(
|
const prompt = getPrompt(
|
||||||
currentQuestion,
|
currentQuestion,
|
||||||
@@ -320,15 +327,18 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
console.log('Question-Action:', currentQuestion, action);
|
console.log('Question-Action:', currentQuestion, action);
|
||||||
|
|
||||||
if (action.action === 'answer') {
|
if (action.action === 'answer') {
|
||||||
context.push({
|
updateContext({
|
||||||
step,
|
step,
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
...action,
|
...action,
|
||||||
});
|
});
|
||||||
|
|
||||||
const evaluation = await evaluateAnswer(currentQuestion, action.answer);
|
const evaluation = await evaluateAnswer(currentQuestion, action.answer);
|
||||||
|
|
||||||
if (currentQuestion === question) {
|
if (currentQuestion === question) {
|
||||||
if (evaluation.is_valid_answer) {
|
if (evaluation.is_valid_answer) {
|
||||||
|
// EXIT POINT
|
||||||
|
await storeContext(prompt, [allContext, allKeywords, allQuestions, allKnowledge], step);
|
||||||
return action;
|
return action;
|
||||||
} else {
|
} else {
|
||||||
badContext.push({
|
badContext.push({
|
||||||
@@ -354,7 +364,7 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
gaps.push(question); // always keep the original question in the gaps
|
gaps.push(question); // always keep the original question in the gaps
|
||||||
} else {
|
} else {
|
||||||
console.log('No new questions to ask');
|
console.log('No new questions to ask');
|
||||||
context.push({
|
updateContext({
|
||||||
step,
|
step,
|
||||||
...action,
|
...action,
|
||||||
result: 'I have tried all possible questions and found no useful information. I must think out of the box or different angle!!!'
|
result: 'I have tried all possible questions and found no useful information. I must think out of the box or different angle!!!'
|
||||||
@@ -388,7 +398,7 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
await sleep(5000);
|
await sleep(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.push({
|
updateContext({
|
||||||
step,
|
step,
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
...action,
|
...action,
|
||||||
@@ -396,20 +406,20 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('No new queries to search');
|
console.log('No new queries to search');
|
||||||
context.push({
|
updateContext({
|
||||||
step,
|
step,
|
||||||
...action,
|
...action,
|
||||||
result: 'I have tried all possible queries and found no new information. I must think out of the box or different angle!!!'
|
result: 'I have tried all possible queries and found no new information. I must think out of the box or different angle!!!'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (action.action === 'read' && action.URLTargets?.length) {
|
} else if (action.action === 'visit' && action.URLTargets?.length) {
|
||||||
const urlResults = await Promise.all(
|
const urlResults = await Promise.all(
|
||||||
action.URLTargets.map(async (url: string) => {
|
action.URLTargets.map(async (url: string) => {
|
||||||
const response = await readUrl(url, jinaToken);
|
const response = await readUrl(url, jinaToken);
|
||||||
return {url, result: response};
|
return {url, result: response};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
context.push({
|
updateContext({
|
||||||
step,
|
step,
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
...action,
|
...action,
|
||||||
@@ -420,7 +430,7 @@ async function getResponse(question: string, tokenBudget: number = 30000000) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
}
|
}
|
||||||
await storeContext(prompt, [context, allKeywords, allQuestions, allKnowledge], step);
|
await storeContext(prompt, [allContext, allKeywords, allQuestions, allKnowledge], step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,13 @@ Evaluation: {
|
|||||||
"reasoning": "The answer is not definitive and fails to provide the requested information. Don't know, can't derive, lack of information is unacceptable,"
|
"reasoning": "The answer is not definitive and fails to provide the requested information. Don't know, can't derive, lack of information is unacceptable,"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Question: "who owns jina ai?"
|
||||||
|
Answer: "The ownership structure of Jina AI is not publicly disclosed."
|
||||||
|
Evaluation: {
|
||||||
|
"is_valid_answer": false,
|
||||||
|
"reasoning": "The answer is not definitive and fails to provide the requested information. Lack of information is unacceptable, more search and deep reasoning is needed."
|
||||||
|
}
|
||||||
|
|
||||||
Now evaluate this pair:
|
Now evaluate this pair:
|
||||||
Question: ${JSON.stringify(question)}
|
Question: ${JSON.stringify(question)}
|
||||||
Answer: ${JSON.stringify(answer)}`;
|
Answer: ${JSON.stringify(answer)}`;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface QueryResult {
|
|||||||
results: SearchResult[];
|
results: SearchResult[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StepData {
|
export interface StepData {
|
||||||
step: number;
|
step: number;
|
||||||
question: string;
|
question: string;
|
||||||
action: string;
|
action: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user