mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.15`: - [[Playground] [Bug] Previous messages now sent to LLM (#188123)](https://github.com/elastic/kibana/pull/188123) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Joe McElroy","email":"joseph.mcelroy@elastic.co"},"sourceCommit":{"committedDate":"2024-07-12T15:37:04Z","message":"[Playground] [Bug] Previous messages now sent to LLM (#188123)\n\n## Summary\r\n\r\nNow that we are using ChatModel, we should be sending previous messages\r\nin the conversation history.\r\n\r\nThis change:\r\n- defines the prompt as a system prompt\r\n- sends all previous conversations into the ChatModel\r\n- sends the question as a separate message\r\n- update the examples to showcase this flow\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"aca82181a81841acbcaa92ae22cb16aa51f4a735","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:EnterpriseSearch","v8.15.0","v8.16.0"],"title":"[Playground] [Bug] Previous messages now sent to LLM","number":188123,"url":"https://github.com/elastic/kibana/pull/188123","mergeCommit":{"message":"[Playground] [Bug] Previous messages now sent to LLM (#188123)\n\n## Summary\r\n\r\nNow that we are using ChatModel, we should be sending previous messages\r\nin the conversation history.\r\n\r\nThis change:\r\n- defines the prompt as a system prompt\r\n- sends all previous conversations into the ChatModel\r\n- sends the question as a separate message\r\n- update the examples to showcase this flow\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"aca82181a81841acbcaa92ae22cb16aa51f4a735"}},"sourceBranch":"main","suggestedTargetBranches":["8.15"],"targetPullRequestStates":[{"branch":"8.15","label":"v8.15.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/188123","number":188123,"mergeCommit":{"message":"[Playground] [Bug] Previous messages now sent to LLM (#188123)\n\n## Summary\r\n\r\nNow that we are using ChatModel, we should be sending previous messages\r\nin the conversation history.\r\n\r\nThis change:\r\n- defines the prompt as a system prompt\r\n- sends all previous conversations into the ChatModel\r\n- sends the question as a separate message\r\n- update the examples to showcase this flow\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [ ] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [ ] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [ ] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"aca82181a81841acbcaa92ae22cb16aa51f4a735"}}]}] BACKPORT--> Co-authored-by: Joe McElroy <joseph.mcelroy@elastic.co>
This commit is contained in:
parent
e6c0563419
commit
98895c5a1b
9 changed files with 109 additions and 94 deletions
|
@ -21,8 +21,8 @@ describe('Prompt function', () => {
|
|||
Instructions:
|
||||
|
||||
- Provide an explanation of the process.
|
||||
- Answer questions truthfully and factually using only the information presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- Answer questions truthfully and factually using only the context presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
- You must always cite the document where the answer was extracted using inline academic citation style [], using the position.
|
||||
- Use markdown format for code examples.
|
||||
- You are correct, factual, precise, and reliable.
|
||||
|
@ -31,8 +31,7 @@ describe('Prompt function', () => {
|
|||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
@ -45,8 +44,8 @@ describe('Prompt function', () => {
|
|||
"
|
||||
<s>[INST]
|
||||
- Explain the significance of the findings.
|
||||
- Answer questions truthfully and factually using only the information presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- Answer questions truthfully and factually using only the context presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
|
||||
- Use markdown format for code examples.
|
||||
- You are correct, factual, precise, and reliable.
|
||||
|
@ -55,10 +54,10 @@ describe('Prompt function', () => {
|
|||
[INST]
|
||||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
[/INST]
|
||||
|
||||
|
||||
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
@ -72,7 +71,7 @@ describe('Prompt function', () => {
|
|||
<instructions>
|
||||
- Summarize the key points of the article.
|
||||
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
|
||||
- Use markdown format for code examples.
|
||||
- You are correct, factual, precise, and reliable.
|
||||
|
@ -82,7 +81,7 @@ describe('Prompt function', () => {
|
|||
{context}
|
||||
</context>
|
||||
|
||||
<input>{question}</input>
|
||||
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
const OpenAIPrompt = (systemInstructions: string) => {
|
||||
const OpenAIPrompt = (systemInstructions: string, question?: boolean) => {
|
||||
return `
|
||||
Instructions:
|
||||
${systemInstructions}
|
||||
|
@ -13,27 +13,26 @@ const OpenAIPrompt = (systemInstructions: string) => {
|
|||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
${question ? 'follow up question: {question}' : ''}
|
||||
`;
|
||||
};
|
||||
|
||||
const MistralPrompt = (systemInstructions: string) => {
|
||||
const MistralPrompt = (systemInstructions: string, question?: boolean) => {
|
||||
return `
|
||||
<s>[INST]${systemInstructions}[/INST] </s>
|
||||
|
||||
[INST]
|
||||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
[/INST]
|
||||
|
||||
${question ? '[INST]follow up question: {question}[/INST]' : ''}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
// https://docs.anthropic.com/claude/docs/use-xml-tags
|
||||
const AnthropicPrompt = (systemInstructions: string) => {
|
||||
const AnthropicPrompt = (systemInstructions: string, question?: boolean) => {
|
||||
return `
|
||||
<instructions>${systemInstructions}</instructions>
|
||||
|
||||
|
@ -41,11 +40,11 @@ const AnthropicPrompt = (systemInstructions: string) => {
|
|||
{context}
|
||||
</context>
|
||||
|
||||
<input>{question}</input>
|
||||
${question ? '<input>{question}</input>' : ''}
|
||||
`;
|
||||
};
|
||||
|
||||
const GeminiPrompt = (systemInstructions: string) => {
|
||||
const GeminiPrompt = (systemInstructions: string, question?: boolean) => {
|
||||
return `
|
||||
Instructions:
|
||||
${systemInstructions}
|
||||
|
@ -53,8 +52,8 @@ const GeminiPrompt = (systemInstructions: string) => {
|
|||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
${question ? 'follow up question: {question}' : ''}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
|
@ -69,10 +68,10 @@ export const Prompt = (instructions: string, options: PromptTemplateOptions): st
|
|||
- ${instructions}
|
||||
${
|
||||
options.context
|
||||
? '- Answer questions truthfully and factually using only the information presented.'
|
||||
? '- Answer questions truthfully and factually using only the context presented.'
|
||||
: ''
|
||||
}
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
${
|
||||
options.citations
|
||||
? '- You must always cite the document where the answer was extracted using inline academic citation style [], using the position.'
|
||||
|
@ -87,7 +86,7 @@ export const Prompt = (instructions: string, options: PromptTemplateOptions): st
|
|||
mistral: MistralPrompt,
|
||||
anthropic: AnthropicPrompt,
|
||||
gemini: GeminiPrompt,
|
||||
}[options.type || 'openai'](systemInstructions);
|
||||
}[options.type || 'openai'](systemInstructions, false);
|
||||
};
|
||||
|
||||
interface QuestionRewritePromptOptions {
|
||||
|
@ -95,11 +94,11 @@ interface QuestionRewritePromptOptions {
|
|||
}
|
||||
|
||||
export const QuestionRewritePrompt = (options: QuestionRewritePromptOptions): string => {
|
||||
const systemInstructions = `Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question. Rewrite the question in the question language. Keep the answer to a single sentence. Do not use quotes.`;
|
||||
const systemInstructions = `Given the following conversation context and a follow up question, rephrase the follow up question to be a standalone question. Rewrite the question in the question language. Keep the answer to a single sentence. Do not use quotes.`;
|
||||
return {
|
||||
openai: OpenAIPrompt,
|
||||
mistral: MistralPrompt,
|
||||
anthropic: AnthropicPrompt,
|
||||
gemini: GeminiPrompt,
|
||||
}[options.type || 'openai'](systemInstructions);
|
||||
}[options.type || 'openai'](systemInstructions, true);
|
||||
};
|
||||
|
|
|
@ -7,12 +7,24 @@
|
|||
|
||||
export type IndicesQuerySourceFields = Record<string, QuerySourceFields>;
|
||||
|
||||
export enum MessageRole {
|
||||
'user' = 'human',
|
||||
'assistant' = 'assistant',
|
||||
'system' = 'system',
|
||||
}
|
||||
|
||||
interface ModelField {
|
||||
field: string;
|
||||
model_id: string;
|
||||
indices: string[];
|
||||
}
|
||||
|
||||
export interface ChatMessage {
|
||||
id: string;
|
||||
role: MessageRole;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface SemanticField {
|
||||
field: string;
|
||||
inferenceId: string;
|
||||
|
|
|
@ -54,8 +54,8 @@ def create_openai_prompt(question, results):
|
|||
Instructions:
|
||||
|
||||
- Your prompt
|
||||
- Answer questions truthfully and factually using only the information presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- Answer questions truthfully and factually using only the context presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
- You must always cite the document where the answer was extracted using inline academic citation style [], using the position.
|
||||
- Use markdown format for code examples.
|
||||
- You are correct, factual, precise, and reliable.
|
||||
|
@ -64,18 +64,17 @@ def create_openai_prompt(question, results):
|
|||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
|
||||
\\"\\"\\"
|
||||
|
||||
return prompt
|
||||
|
||||
def generate_openai_completion(user_prompt):
|
||||
def generate_openai_completion(user_prompt, question):
|
||||
response = openai_client.chat.completions.create(
|
||||
model=\\"gpt-3.5-turbo\\",
|
||||
messages=[
|
||||
{\\"role\\": \\"system\\", \\"content\\": \\"You are an assistant for question-answering tasks.\\"},
|
||||
{\\"role\\": \\"user\\", \\"content\\": user_prompt},
|
||||
{\\"role\\": \\"system\\", \\"content\\": user_prompt},
|
||||
{\\"role\\": \\"user\\", \\"content\\": question},
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -84,8 +83,8 @@ def generate_openai_completion(user_prompt):
|
|||
if __name__ == \\"__main__\\":
|
||||
question = \\"my question\\"
|
||||
elasticsearch_results = get_elasticsearch_results(question)
|
||||
context_prompt = create_openai_prompt(question, elasticsearch_results)
|
||||
openai_completion = generate_openai_completion(context_prompt)
|
||||
context_prompt = create_openai_prompt(elasticsearch_results)
|
||||
openai_completion = generate_openai_completion(context_prompt, question)
|
||||
print(openai_completion)
|
||||
|
||||
"
|
||||
|
|
|
@ -43,8 +43,8 @@ ANSWER_PROMPT = ChatPromptTemplate.from_template(
|
|||
Instructions:
|
||||
|
||||
- Your prompt
|
||||
- Answer questions truthfully and factually using only the information presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer!
|
||||
- Answer questions truthfully and factually using only the context presented.
|
||||
- If you don't know the answer, just say that you don't know, don't make up an answer.
|
||||
- You must always cite the document where the answer was extracted using inline academic citation style [], using the position.
|
||||
- Use markdown format for code examples.
|
||||
- You are correct, factual, precise, and reliable.
|
||||
|
@ -53,8 +53,7 @@ ANSWER_PROMPT = ChatPromptTemplate.from_template(
|
|||
Context:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Answer:
|
||||
|
||||
\\"\\"\\"
|
||||
)
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ def create_openai_prompt(question, results):
|
|||
|
||||
return prompt
|
||||
|
||||
def generate_openai_completion(user_prompt):
|
||||
def generate_openai_completion(user_prompt, question):
|
||||
response = openai_client.chat.completions.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are an assistant for question-answering tasks."},
|
||||
{"role": "user", "content": user_prompt},
|
||||
{"role": "system", "content": user_prompt},
|
||||
{"role": "user", "content": question},
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -72,8 +72,8 @@ def generate_openai_completion(user_prompt):
|
|||
if __name__ == "__main__":
|
||||
question = "my question"
|
||||
elasticsearch_results = get_elasticsearch_results(question)
|
||||
context_prompt = create_openai_prompt(question, elasticsearch_results)
|
||||
openai_completion = generate_openai_completion(context_prompt)
|
||||
context_prompt = create_openai_prompt(elasticsearch_results)
|
||||
openai_completion = generate_openai_completion(context_prompt, question)
|
||||
print(openai_completion)
|
||||
|
||||
`}
|
||||
|
|
|
@ -22,7 +22,7 @@ import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-
|
|||
import { AppMountParameters } from '@kbn/core/public';
|
||||
import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
|
||||
import { ChatRequestData } from '../common/types';
|
||||
import { ChatRequestData, MessageRole } from '../common/types';
|
||||
import type { App } from './components/app';
|
||||
import type { PlaygroundProvider as PlaygroundProviderComponent } from './providers/playground_provider';
|
||||
import { PlaygroundHeaderDocs } from './components/playground_header_docs';
|
||||
|
@ -80,12 +80,6 @@ export interface ChatForm {
|
|||
[ChatFormFields.queryFields]: { [index: string]: string[] };
|
||||
}
|
||||
|
||||
export enum MessageRole {
|
||||
'user' = 'human',
|
||||
'assistant' = 'assistant',
|
||||
'system' = 'system',
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
id: string;
|
||||
content: string | React.ReactNode;
|
||||
|
|
|
@ -9,9 +9,10 @@ import type { Client } from '@elastic/elasticsearch';
|
|||
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
import { ChatPromptTemplate } from '@langchain/core/prompts';
|
||||
import { FakeListChatModel, FakeStreamingLLM } from '@langchain/core/utils/testing';
|
||||
import { Message, experimental_StreamData } from 'ai';
|
||||
import { experimental_StreamData } from 'ai';
|
||||
import { createAssist as Assist } from '../utils/assist';
|
||||
import { ConversationalChain, clipContext } from './conversational_chain';
|
||||
import { ChatMessage, MessageRole } from '../types';
|
||||
|
||||
describe('conversational chain', () => {
|
||||
const createTestChain = async ({
|
||||
|
@ -28,7 +29,7 @@ describe('conversational chain', () => {
|
|||
modelLimit,
|
||||
}: {
|
||||
responses: string[];
|
||||
chat: Message[];
|
||||
chat: ChatMessage[];
|
||||
expectedFinalAnswer: string;
|
||||
expectedDocs: any;
|
||||
expectedTokens: any;
|
||||
|
@ -96,8 +97,8 @@ describe('conversational chain', () => {
|
|||
size: 3,
|
||||
inputTokensLimit: modelLimit,
|
||||
},
|
||||
prompt: 'you are a QA bot {question} {chat_history} {context}',
|
||||
questionRewritePrompt: 'rewrite question {question} using {chat_history}"',
|
||||
prompt: 'you are a QA bot {context}',
|
||||
questionRewritePrompt: 'rewrite question {question} using {context}"',
|
||||
});
|
||||
|
||||
const stream = await conversationalChain.stream(aiClient, chat);
|
||||
|
@ -146,7 +147,7 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -180,7 +181,7 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -215,7 +216,7 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -266,17 +267,17 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
role: 'assistant',
|
||||
role: MessageRole.assistant,
|
||||
content: 'the final answer',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -292,7 +293,7 @@ describe('conversational chain', () => {
|
|||
],
|
||||
expectedTokens: [
|
||||
{ type: 'context_token_count', count: 15 },
|
||||
{ type: 'prompt_token_count', count: 38 },
|
||||
{ type: 'prompt_token_count', count: 39 },
|
||||
],
|
||||
expectedSearchRequest: [
|
||||
{
|
||||
|
@ -310,17 +311,17 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
role: 'assistant',
|
||||
role: MessageRole.assistant,
|
||||
content: 'the final answer',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -336,7 +337,7 @@ describe('conversational chain', () => {
|
|||
],
|
||||
expectedTokens: [
|
||||
{ type: 'context_token_count', count: 15 },
|
||||
{ type: 'prompt_token_count', count: 40 },
|
||||
{ type: 'prompt_token_count', count: 39 },
|
||||
],
|
||||
expectedSearchRequest: [
|
||||
{
|
||||
|
@ -354,17 +355,17 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
role: 'assistant',
|
||||
role: MessageRole.assistant,
|
||||
content: 'the final answer',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -380,7 +381,7 @@ describe('conversational chain', () => {
|
|||
],
|
||||
expectedTokens: [
|
||||
{ type: 'context_token_count', count: 15 },
|
||||
{ type: 'prompt_token_count', count: 42 },
|
||||
{ type: 'prompt_token_count', count: 49 },
|
||||
],
|
||||
expectedSearchRequest: [
|
||||
{
|
||||
|
@ -399,17 +400,17 @@ describe('conversational chain', () => {
|
|||
chat: [
|
||||
{
|
||||
id: '1',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
role: 'assistant',
|
||||
role: MessageRole.assistant,
|
||||
content: 'the final answer',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
role: 'user',
|
||||
role: MessageRole.user,
|
||||
content: 'what is the work from home policy?',
|
||||
},
|
||||
],
|
||||
|
@ -445,8 +446,8 @@ describe('conversational chain', () => {
|
|||
],
|
||||
// Even with body_content of 1000, the token count should be below or equal to model limit of 100
|
||||
expectedTokens: [
|
||||
{ type: 'context_token_count', count: 70 },
|
||||
{ type: 'prompt_token_count', count: 97 },
|
||||
{ type: 'context_token_count', count: 65 },
|
||||
{ type: 'prompt_token_count', count: 99 },
|
||||
],
|
||||
expectedHasClipped: true,
|
||||
expectedSearchRequest: [
|
||||
|
|
|
@ -7,16 +7,18 @@
|
|||
|
||||
import { SearchHit } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Document } from '@langchain/core/documents';
|
||||
import { ChatPromptTemplate, PromptTemplate } from '@langchain/core/prompts';
|
||||
import {
|
||||
ChatPromptTemplate,
|
||||
PromptTemplate,
|
||||
SystemMessagePromptTemplate,
|
||||
} from '@langchain/core/prompts';
|
||||
import { Runnable, RunnableLambda, RunnableSequence } from '@langchain/core/runnables';
|
||||
import { BytesOutputParser, StringOutputParser } from '@langchain/core/output_parsers';
|
||||
import {
|
||||
createStreamDataTransformer,
|
||||
experimental_StreamData,
|
||||
Message as VercelChatMessage,
|
||||
} from 'ai';
|
||||
import { createStreamDataTransformer, experimental_StreamData } from 'ai';
|
||||
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
||||
import { BaseMessage } from '@langchain/core/messages';
|
||||
import { HumanMessage, AIMessage } from '@langchain/core/messages';
|
||||
import { ChatMessage, MessageRole } from '../types';
|
||||
import { ElasticsearchRetriever } from './elasticsearch_retriever';
|
||||
import { renderTemplate } from '../utils/render_template';
|
||||
|
||||
|
@ -47,19 +49,27 @@ interface ContextInputs {
|
|||
question: string;
|
||||
}
|
||||
|
||||
const formatVercelMessages = (chatHistory: VercelChatMessage[]) => {
|
||||
const getSerialisedMessages = (chatHistory: ChatMessage[]) => {
|
||||
const formattedDialogueTurns = chatHistory.map((message) => {
|
||||
if (message.role === 'user') {
|
||||
if (message.role === MessageRole.user) {
|
||||
return `Human: ${message.content}`;
|
||||
} else if (message.role === 'assistant') {
|
||||
} else if (message.role === MessageRole.assistant) {
|
||||
return `Assistant: ${message.content}`;
|
||||
} else {
|
||||
return `${message.role}: ${message.content}`;
|
||||
}
|
||||
});
|
||||
return formattedDialogueTurns.join('\n');
|
||||
};
|
||||
|
||||
const getMessages = (chatHistory: ChatMessage[]) => {
|
||||
return chatHistory.map((message) => {
|
||||
if (message.role === 'human') {
|
||||
return new HumanMessage(message.content);
|
||||
} else {
|
||||
return new AIMessage(message.content);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const buildContext = (docs: Document[]) => {
|
||||
const serializedDocs = docs.map((doc, i) =>
|
||||
renderTemplate(
|
||||
|
@ -127,7 +137,7 @@ class ConversationalChainFn {
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
async stream(client: AssistClient, msgs: VercelChatMessage[]) {
|
||||
async stream(client: AssistClient, msgs: ChatMessage[]) {
|
||||
const data = new experimental_StreamData();
|
||||
|
||||
const messages = msgs ?? [];
|
||||
|
@ -136,7 +146,7 @@ class ConversationalChainFn {
|
|||
const retrievedDocs: Document[] = [];
|
||||
|
||||
let retrievalChain: Runnable = RunnableLambda.from(() => '');
|
||||
const chatHistory = formatVercelMessages(previousMessages);
|
||||
const chatHistory = getSerialisedMessages(previousMessages);
|
||||
|
||||
if (this.options.rag) {
|
||||
const retriever = new ElasticsearchRetriever({
|
||||
|
@ -161,8 +171,7 @@ class ConversationalChainFn {
|
|||
);
|
||||
standaloneQuestionChain = RunnableSequence.from([
|
||||
{
|
||||
context: () => '',
|
||||
chat_history: (input) => input.chat_history,
|
||||
context: (input) => input.chat_history,
|
||||
question: (input) => input.question,
|
||||
},
|
||||
questionRewritePromptTemplate,
|
||||
|
@ -175,12 +184,15 @@ class ConversationalChainFn {
|
|||
});
|
||||
}
|
||||
|
||||
const prompt = ChatPromptTemplate.fromTemplate(this.options.prompt);
|
||||
const lcMessages = getMessages(messages);
|
||||
const prompt = ChatPromptTemplate.fromMessages([
|
||||
SystemMessagePromptTemplate.fromTemplate(this.options.prompt),
|
||||
...lcMessages,
|
||||
]);
|
||||
|
||||
const answerChain = RunnableSequence.from([
|
||||
{
|
||||
context: RunnableSequence.from([(input) => input.question, retrievalChain]),
|
||||
chat_history: (input) => input.chat_history,
|
||||
question: (input) => input.question,
|
||||
},
|
||||
RunnableLambda.from(clipContext(this.options?.rag?.inputTokensLimit, prompt, data)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue