fix: improve eval

This commit is contained in:
Han Xiao
2025-02-15 12:44:32 +08:00
parent 13d38e304d
commit 686e6723b2
3 changed files with 49 additions and 37 deletions

View File

@@ -68,7 +68,8 @@ You can use it with any OpenAI-compatible client. For the authentication Bearer,
If you are building a web/local/mobile client that uses `Jina DeepSearch API`, here are some design guidelines: If you are building a web/local/mobile client that uses `Jina DeepSearch API`, here are some design guidelines:
- Our API is fully compatible with [OpenAI API schema](https://platform.openai.com/docs/api-reference/chat/create), this should greatly simplify the integration process. The model name is `jina-deepsearch-v1`. - Our API is fully compatible with [OpenAI API schema](https://platform.openai.com/docs/api-reference/chat/create), this should greatly simplify the integration process. The model name is `jina-deepsearch-v1`.
- Our DeepSearch API is a reasoning+search grounding LLM, so it's best for questions that require deep reasoning and search. - Our DeepSearch API is a reasoning+search grounding LLM, so it's best for questions that require deep reasoning and search.
- Two special tokens are introduced `<think>...</think>`, `<references>...</references>`. Please render them with care. - Two special tokens are introduced `<think>...</think>`. Please render them with care.
- Citations are often provided, and in [Github-flavored markdown footnote format](https://github.blog/changelog/2021-09-30-footnotes-now-supported-in-markdown-fields/), e.g. `[^1]`, `[^2]`, ...
- Guide the user to get a Jina API key from https://jina.ai, with 1M free tokens for new API key. - Guide the user to get a Jina API key from https://jina.ai, with 1M free tokens for new API key.
- There are rate limits, [between 10RPM to 30RPM depending on the API key tier](https://jina.ai/contact-sales#rate-limit). - There are rate limits, [between 10RPM to 30RPM depending on the API key tier](https://jina.ai/contact-sales#rate-limit).
- [Download Jina AI logo here](https://jina.ai/logo-Jina-1024.zip) - [Download Jina AI logo here](https://jina.ai/logo-Jina-1024.zip)

View File

@@ -76,6 +76,7 @@ function getSchema(allowReflect: boolean, allowRead: boolean, allowAnswer: boole
function getPrompt( function getPrompt(
question: string, question: string,
context?: string[], context?: string[],
allChatHistory?: { user: string, assistant: string }[],
allQuestions?: string[], allQuestions?: string[],
allKeywords?: string[], allKeywords?: string[],
allowReflect: boolean = true, allowReflect: boolean = true,
@@ -101,15 +102,20 @@ ${question}
</question> </question>
`); `);
// Add context section if exists // add chat history if exist
if (context?.length) { if (allChatHistory?.length) {
sections.push(` sections.push(`
You have conducted the following actions: You have conducted the following chat history with the user:
<context> <chat-history>
${context.join('\n')} ${allChatHistory.map(({user, assistant}) => `
<user>
</context> ${user}
`); </user>
<you>
${assistant}
</you>
`).join('\n')}
</chat-history>`);
} }
// Add knowledge section if exists // Add knowledge section if exists
@@ -142,6 +148,19 @@ ${knowledgeItems}
`); `);
} }
// Add context section if exists
if (context?.length) {
sections.push(`
You have conducted the following actions:
<context>
${context.join('\n')}
</context>
`);
}
// Add bad context section if exists // Add bad context section if exists
if (badContext?.length) { if (badContext?.length) {
const attempts = badContext const attempts = badContext
@@ -159,7 +178,7 @@ ${knowledgeItems}
const learnedStrategy = badContext.map(c => c.improvement).join('\n'); const learnedStrategy = badContext.map(c => c.improvement).join('\n');
sections.push(` sections.push(`
Your have tried the following actions but failed to find the answer to the question: Also, you have tried the following actions but failed to find the answer to the question:
<bad-attempts> <bad-attempts>
${attempts} ${attempts}
@@ -303,6 +322,7 @@ export async function getResponse(question: string,
const gaps: string[] = [question]; // All questions to be answered including the orginal question const gaps: string[] = [question]; // All questions to be answered including the orginal question
const allQuestions = [question]; const allQuestions = [question];
const allKeywords = []; const allKeywords = [];
const allChatHistory: { user: string, assistant: string }[] = [];
const allKnowledge: KnowledgeItem[] = []; // knowledge are intermedidate questions that are answered const allKnowledge: KnowledgeItem[] = []; // knowledge are intermedidate questions that are answered
// iterate over historyMessages // iterate over historyMessages
// if role is user and content is question, add to allQuestions, the next assistant content should be the answer // if role is user and content is question, add to allQuestions, the next assistant content should be the answer
@@ -310,12 +330,15 @@ export async function getResponse(question: string,
historyMessages?.forEach((message, i) => { historyMessages?.forEach((message, i) => {
if (message.role === 'user' && message.content && historyMessages[i + 1]?.role === 'assistant') { if (message.role === 'user' && message.content && historyMessages[i + 1]?.role === 'assistant') {
allQuestions.push(message.content as string) allQuestions.push(message.content as string)
allKnowledge.push({ const answerContent = (historyMessages[i + 1]?.content || '') as string;
question: message.content as string, // Remove <think></think> tags and their content using regex
answer: (historyMessages[i + 1]?.content || '') as string, const cleanedAnswer = answerContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
type: 'chat-history', if (cleanedAnswer) {
updated: new Date().toISOString() allChatHistory.push({
}); user: message.content as string,
assistant: cleanedAnswer,
});
}
} }
}) })
@@ -353,6 +376,7 @@ export async function getResponse(question: string,
prompt = getPrompt( prompt = getPrompt(
currentQuestion, currentQuestion,
diaryContext, diaryContext,
allChatHistory,
allQuestions, allQuestions,
allKeywords, allKeywords,
allowReflect, allowReflect,
@@ -693,6 +717,7 @@ You decided to think out of the box or cut from a completely different angle.`);
const prompt = getPrompt( const prompt = getPrompt(
question, question,
diaryContext, diaryContext,
allChatHistory,
allQuestions, allQuestions,
allKeywords, allKeywords,
false, false,

View File

@@ -28,35 +28,21 @@ app.get('/health', (req, res) => {
}); });
function buildMdFromAnswer(answer: AnswerAction) { function buildMdFromAnswer(answer: AnswerAction) {
if (!answer.references?.length || !answer.references.some(ref => ref.url.startsWith('http'))) { if (!answer.references?.length) {
return answer.answer; return answer.answer;
} }
const references = answer.references.map((ref, i) => { const references = answer.references.map((ref, i) => {
// Clean up the quote text // Clean up the quote text
const cleanQuote = ref.exactQuote const cleanQuote = ref.exactQuote
// Remove HTML artifacts .replace(/[^a-zA-Z0-9]+/g, ' ')
.replace(/<[^>]+>/g, '')
// Remove multiple spaces
.replace(/\s+/g, ' ')
// Remove special characters and markdown conflicts
.replace(/[[\]_*`]/g, '')
// Clean up any remaining artifacts
.replace(/=+/g, '')
.replace(/_[^_]+_/g, '$1')
// Remove navigation artifacts
.replace(/arrow_drop_down/g, '')
.replace(/language/g, '')
// Trim whitespace
.trim(); .trim();
// If the quote is too long, truncate it if (ref.url.startsWith('http')) {
const maxLength = 20; return `[^${i + 1}]: [${cleanQuote}](${ref.url})`;
const truncatedQuote = cleanQuote.length > maxLength } else {
? cleanQuote.substring(0, maxLength) + '...' return `[^${i + 1}]: ${cleanQuote}`;
: cleanQuote; }
return `[^${i + 1}]: [${truncatedQuote}](${ref.url})`;
}).join('\n\n'); }).join('\n\n');
return ` return `